Authorization Code Flow + PKCE
The Authorization Code flow is the recommended OAuth2 grant type for web applications, SPAs, and native apps. Autentico supports PKCE (RFC 7636) for public clients that cannot securely store a client secret.
Flow overview
Section titled “Flow overview”Step 1: Generate PKCE parameters
Section titled “Step 1: Generate PKCE parameters”PKCE is required for public clients and recommended for all clients.
function generateCodeVerifier() { const array = new Uint8Array(32); crypto.getRandomValues(array); return btoa(String.fromCharCode(...array)) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');}
async function generateCodeChallenge(verifier) { const data = new TextEncoder().encode(verifier); const digest = await crypto.subtle.digest('SHA-256', data); return btoa(String.fromCharCode(...new Uint8Array(digest))) .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');}
const codeVerifier = generateCodeVerifier();// Store codeVerifier for the token exchange stepsessionStorage.setItem('code_verifier', codeVerifier);const codeChallenge = await generateCodeChallenge(codeVerifier);Step 2: Authorization request
Section titled “Step 2: Authorization request”Redirect the user’s browser to the authorization endpoint:
GET /oauth2/authorize ?response_type=code &client_id=YOUR_CLIENT_ID &redirect_uri=https://yourapp.com/callback &scope=openid profile email &state=RANDOM_STATE_VALUE &nonce=RANDOM_NONCE_VALUE &code_challenge=PKCE_CHALLENGE &code_challenge_method=S256| Parameter | Required | Description |
|---|---|---|
response_type | Yes | Must be code |
client_id | Yes | Your registered client ID |
redirect_uri | Yes | Must exactly match a registered redirect URI |
scope | Yes | Space-separated scopes. Must include openid for OIDC. |
state | Recommended | Opaque value for CSRF protection. Returned unchanged. |
nonce | Recommended | Opaque value embedded in the ID token to prevent replay attacks. |
code_challenge | Required for public clients | Base64url-encoded SHA-256 hash of code_verifier |
code_challenge_method | Required with code_challenge | S256 (recommended) or plain |
Step 3: User authenticates
Section titled “Step 3: User authenticates”Autentico renders the login page. After successful authentication (including MFA if enabled), the user is redirected to your redirect_uri:
https://yourapp.com/callback ?code=AUTHORIZATION_CODE &state=RANDOM_STATE_VALUEVerify that state matches what you sent. The authorization code is short-lived (default 10 minutes) and single-use.
Step 4: Token exchange
Section titled “Step 4: Token exchange”Exchange the authorization code for tokens at the token endpoint.
curl -X POST https://auth.example.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "client_id=YOUR_CLIENT_ID" \ -d "code=AUTHORIZATION_CODE" \ -d "redirect_uri=https://yourapp.com/callback" \ -d "code_verifier=YOUR_CODE_VERIFIER"curl -X POST https://auth.example.com/oauth2/token \ -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=AUTHORIZATION_CODE" \ -d "redirect_uri=https://yourapp.com/callback"curl -X POST https://auth.example.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "client_id=YOUR_CLIENT_ID" \ -d "client_secret=YOUR_CLIENT_SECRET" \ -d "code=AUTHORIZATION_CODE" \ -d "redirect_uri=https://yourapp.com/callback"Response:
{ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 900, "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}The id_token is a JWT containing identity claims about the authenticated user. See Token Structure & Claims for details.
Keycloak-compatible path
Section titled “Keycloak-compatible path”Autentico also registers the Keycloak-compatible token endpoint:
POST /oauth2/protocol/openid-connect/tokenThis allows existing Keycloak client integrations to work by changing only the base URL.