Skip to main content

Complete OAuth 2.1 Flow

Auth-Agent implements the OAuth 2.1 Authorization Code Flow with PKCE (Proof Key for Code Exchange). Here’s how it works:

Step-by-Step Breakdown

1

1. Generate Login URL

When user clicks sign-in, the SDK generates a PKCE code verifier and challenge:
// Generate random 32-byte verifier
const codeVerifier = base64url(crypto.randomBytes(32));

// Create SHA-256 challenge
const codeChallenge = base64url(sha256(codeVerifier));

// Store verifier for later
sessionStorage.setItem('code_verifier', codeVerifier);
Then constructs the authorization URL with the challenge.
2

2. Redirect to Auth Server

Browser redirects to:
GET /oauth2/authorize?
  client_id=your_agent_id&
  redirect_uri=http://localhost:3000/callback&
  response_type=code&
  scope=openid+profile+email&
  code_challenge=<base64url_challenge>&
  code_challenge_method=S256&
  state=<random_csrf_token>
The state parameter protects against CSRF attacks.
3

3. User Authenticates

The Auth-Agent server displays an authentication page where the user enters:
  • Agent ID: Their registered agent identifier
  • Agent Secret: Their secure password
  • Model Name: The AI model being used
The server verifies these credentials against the database.
4

4. Generate Authorization Code

If authentication succeeds:
  • Server creates an auth session
  • Stores the PKCE code_challenge
  • Generates a one-time authorization_code
  • Redirects back to your app
HTTP/1.1 302 Found
Location: http://localhost:3000/callback?
  code=AUTH_CODE_HERE&
  state=<same_state>
5

5. Exchange Code for Tokens

Your app’s callback handler receives the code and exchanges it for tokens:
POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AUTH_CODE_HERE&
client_id=your_agent_id&
redirect_uri=http://localhost:3000/callback&
code_verifier=<original_verifier>
The authorization code can only be used once and expires in 10 minutes.
6

6. Verify PKCE

Server verifies the PKCE proof:
// Server computes challenge from verifier
const computed = base64url(sha256(code_verifier));

// Compare with stored challenge
if (computed === stored_code_challenge) {
  // ✓ PKCE verified!
  // Issue tokens
}
This proves the same client that started the flow is completing it.
7

7. Issue Tokens

Server responds with tokens:
{
  "access_token": "eyJhbGci...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "eyJhbGci...",
  "scope": "openid profile email"
}
access_token
string
JWT token for accessing protected resources (expires in 1 hour)
refresh_token
string
Long-lived token for refreshing access tokens (expires in 30 days)
8

8. Store Tokens

SDK stores tokens securely:
// Calculate expiration time
const expiresAt = Date.now() + (expires_in * 1000);

// Store in localStorage (or sessionStorage/memory)
localStorage.setItem('auth_agent_tokens', JSON.stringify({
  access_token,
  refresh_token,
  expires_at: expiresAt,
  scope,
}));
9

9. Fetch User Info

SDK makes an authenticated request to get user details:
GET /oauth2/userinfo
Authorization: Bearer <access_token>
Response:
{
  "sub": "agent_id",
  "agent_id": "my_agent_123",
  "name": "John Doe",
  "email": "john@example.com",
  "model_name": "gpt-4",
  "permissions": ["read", "write"]
}
10

10. Schedule Auto-Refresh

SDK schedules automatic token refresh 5 minutes before expiration:
const timeUntilRefresh = expiresAt - Date.now() - (5 * 60 * 1000);

setTimeout(async () => {
  await client.refreshToken();
}, timeUntilRefresh);

Token Refresh Flow

When the access token is about to expire:

Refresh Request

POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
refresh_token=<refresh_token>&
client_id=your_agent_id

Refresh Response

{
  "access_token": "new_eyJhbGci...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid profile email"
}
Refresh tokens are NOT rotated by default. The same refresh token can be used multiple times until it expires.

Security Features

PKCE prevents authorization code interception attacks:
  • Attacker cannot use a stolen code without the verifier
  • Even if code is intercepted, it’s useless without the PKCE verifier
  • Verifier never leaves the client, only challenge is sent
Required by OAuth 2.1 for all clients.
Protects against CSRF (Cross-Site Request Forgery) attacks: - Random state generated for each request - Stored in sessionStorage - Verified when handling callback - Prevents attackers from initiating unauthorized auth flows
Tokens are stored securely: - localStorage: Persistent across browser sessions - sessionStorage: Cleared when tab/browser closes - memory: Only in JavaScript memory (most secure but not persistent) Note: Even with localStorage, tokens are HttpOnly-equivalent because they’re only accessible to your origin.
Tokens have limited lifetimes: - Access tokens: 1 hour - Refresh tokens: 30 days - Authorization codes: 10 minutes - Auth sessions: 10 minutes (for challenge completion) Automatic refresh keeps users logged in without re-authentication.
Prevents open redirect vulnerabilities:
  • Redirect URI must exactly match registered URI
  • Protocol, domain, port, and path must all match
  • No wildcard or pattern matching

Error Scenarios

  • Invalid Credentials
  • PKCE Verification Failed
  • Expired Code
  • Redirect URI Mismatch
{
  "error": "invalid_credentials",
  "error_description": "Invalid agent credentials"
}
Cause: Wrong agent_id or agent_secretSolution: Verify credentials or register new agent

Next Steps