Documentation Index Fetch the complete documentation index at: https://docs.auth-agent.com/llms.txt
Use this file to discover all available pages before exploring further.
For Website Developers
This guide shows you how to integrate Auth Agent into your website to allow AI agents to authenticate.
Step 1: Register OAuth Client
Before integrating, you need credentials:
Navigate to Website Console
Register New Client
Click “Register New Client” and provide:
Client name (e.g., “My Website”)
Redirect URIs (e.g., https://example.com/api/auth/callback/auth-agent)
Copy Credentials
Save your client_id and client_secret to your environment variables
Step 2: Choose Your Integration Method
If you use Better Auth , integration takes 2 minutes. Install the Plugin npm install auth-agent-better-auth
Add to Your Auth Config // lib/auth.ts
import { betterAuth } from "better-auth" ;
import { authAgent } from "auth-agent-better-auth/server" ;
export const auth = betterAuth ({
database: /* your database */ ,
plugins: [
authAgent ({
clientId: process . env . AUTH_AGENT_CLIENT_ID ! ,
clientSecret: process . env . AUTH_AGENT_CLIENT_SECRET ! ,
scenario: "fullAccount" , // or "contextualProfile" or "freshProfile"
})
]
});
// app/login/page.tsx
import { AuthAgentButton } from "auth-agent-better-auth/components" ;
export default function LoginPage () {
return (
< div >
< h1 > Sign In </ h1 >
< AuthAgentButton callbackURL = "/dashboard" />
</ div >
);
}
That’s It The plugin handles:
OAuth 2.1 authorization flow
PKCE challenge generation
Token exchange
Session creation
All three integration scenarios
npm: auth-agent-better-auth View package documentation
For custom auth systems or frameworks without Better Auth support. Overview When an AI agent wants to access your website:
The agent navigates to your sign-in page
Clicks “Sign in with Auth Agent”
You redirect to Auth Agent’s authorization page
The agent authenticates (handled automatically)
Auth Agent redirects back with an authorization code
You exchange the code for tokens
You create a session based on your chosen scenario
// components/AuthAgentButton.tsx
'use client' ;
export function AuthAgentButton () {
const handleSignIn = async () => {
// Generate PKCE challenge
const codeVerifier = generateRandomString ( 128 );
const codeChallenge = await sha256 ( codeVerifier );
const state = generateRandomString ( 32 );
// Store for callback
sessionStorage . setItem ( 'code_verifier' , codeVerifier );
sessionStorage . setItem ( 'oauth_state' , state );
const params = new URLSearchParams ({
client_id: process . env . NEXT_PUBLIC_AUTH_AGENT_CLIENT_ID ! ,
redirect_uri: ` ${ window . location . origin } /api/auth/callback` ,
response_type: 'code' ,
state ,
code_challenge: codeChallenge ,
code_challenge_method: 'S256' ,
scope: 'openid profile email' ,
});
window . location . href = `https://api.auth-agent.com/authorize? ${ params } ` ;
};
return (
< button onClick = { handleSignIn } >
Sign in with Auth Agent
</ button >
);
}
Handle Callback // app/api/auth/callback/route.ts
import { NextRequest , NextResponse } from 'next/server' ;
export async function GET ( request : NextRequest ) {
const { searchParams } = new URL ( request . url );
const code = searchParams . get ( 'code' );
const state = searchParams . get ( 'state' );
// Validate state (from your session/cookie)
// Get code_verifier from session
// Exchange code for tokens
const tokenResponse = await fetch ( 'https://api.auth-agent.com/token' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/x-www-form-urlencoded' },
body: new URLSearchParams ({
grant_type: 'authorization_code' ,
code ,
redirect_uri: ` ${ process . env . NEXT_PUBLIC_BASE_URL } /api/auth/callback` ,
client_id: process . env . AUTH_AGENT_CLIENT_ID ! ,
client_secret: process . env . AUTH_AGENT_CLIENT_SECRET ! ,
code_verifier: codeVerifier ,
}),
});
const tokens = await tokenResponse . json ();
// Get user info
const userResponse = await fetch ( 'https://api.auth-agent.com/userinfo' , {
headers: { Authorization: `Bearer ${ tokens . access_token } ` },
});
const userInfo = await userResponse . json ();
// Create session based on your scenario
// userInfo.email - user's email
// userInfo.sub - agent ID
return NextResponse . redirect ( '/dashboard' );
}
See the full manual integration examples below for each scenario.
Integration Scenarios
Auth Agent supports three patterns for how agents interact with user accounts:
Full Account Access Agent uses user’s existing account
Contextual Profile Separate agent profile with user context
Fresh Profile Independent agent profile
Comparison
Feature Full Account Contextual Profile Fresh Profile Call /userinfo Required Required Not needed User Email Access Yes Yes No Access to User Data Full Read-only None Agent Attribution No Yes Yes Privacy Level Low Medium High
Scenario 1: Full Account Access
Use when: The agent needs full access to the user’s existing account (e.g., e-commerce, banking).
Better Auth Config
authAgent ({
clientId: process . env . AUTH_AGENT_CLIENT_ID ! ,
clientSecret: process . env . AUTH_AGENT_CLIENT_SECRET ! ,
scenario: "fullAccount" ,
})
Manual Implementation
// In your callback handler
const userInfo = await fetch ( 'https://api.auth-agent.com/userinfo' , {
headers: { Authorization: `Bearer ${ tokens . access_token } ` },
}). then ( r => r . json ());
// Find existing user by email
const user = await db . users . findOne ({ email: userInfo . email });
if ( ! user ) {
return NextResponse . redirect ( '/auth/register' );
}
// Create session for existing user
await createSession ({ userId: user . id , agentId: userInfo . sub });
Scenario 2: Contextual Profile
Use when: You want separate agent profiles but need access to user context (e.g., social media, content platforms).
Better Auth Config
authAgent ({
clientId: process . env . AUTH_AGENT_CLIENT_ID ! ,
clientSecret: process . env . AUTH_AGENT_CLIENT_SECRET ! ,
scenario: "contextualProfile" ,
})
Manual Implementation
// In your callback handler
const userInfo = await fetch ( 'https://api.auth-agent.com/userinfo' , {
headers: { Authorization: `Bearer ${ tokens . access_token } ` },
}). then ( r => r . json ());
// Find or create user
const user = await db . users . findOrCreate ({ email: userInfo . email });
// Create agent profile linked to user
const agentProfile = await db . agentProfiles . create ({
agentId: userInfo . sub ,
linkedUserId: user . id ,
});
// Agent can read user data but actions are attributed to agent
await createSession ({
agentProfileId: agentProfile . id ,
linkedUserId: user . id
});
Scenario 3: Fresh Profile
Use when: You want completely independent agent profiles with no user context (e.g., privacy-focused services).
Better Auth Config
authAgent ({
clientId: process . env . AUTH_AGENT_CLIENT_ID ! ,
clientSecret: process . env . AUTH_AGENT_CLIENT_SECRET ! ,
scenario: "freshProfile" ,
})
Manual Implementation
// In your callback handler
// DO NOT call /userinfo - extract agent ID from JWT instead
const decoded = jwt . decode ( tokens . access_token );
const agentId = decoded . sub ;
// Create fresh agent profile (no user linkage)
const agentProfile = await db . agentProfiles . create ({
agentId ,
// No linkedUserId - completely independent
});
await createSession ({ agentProfileId: agentProfile . id });
Decision Guide
Does the agent need to act on the user's behalf?
Yes → Full Account AccessNo → Continue
Does the agent need user context or preferences?
Yes → Contextual ProfileNo → Fresh Profile
Next Steps
Integration Scenarios Detailed guide with diagrams
API Reference Complete endpoint documentation
Security Best Practices Secure your integration
GitHub Examples View example implementations