Authorization Code Flow with PKCE
The Authorization Code flow with PKCE (Proof Key for Code Exchange) is the primary way applications authenticate users through Aero2. PKCE prevents authorization code interception attacks and is mandatory in Aero2.
Flow Diagram
- 1Browser → Your AppUser clicks Login
- 2Your AppGenerate PKCE code_verifier + code_challengecrypto.getRandomValues() + SHA-256
- 3Your App → Aero2Redirect to /oauth2/authorize?client_id=...&redirect_uri=...&code_challenge=...&code_challenge_method=S256&response_type=code&scope=openid+profile+email
- 4Aero2 → BrowserShow login pageUser authenticates with identity provider
- 5Aero2 → Your AppRedirect to redirect_uri with code?code=abc123&state=xyz
- 6Your App → Aero2Exchange code for tokensPOST /oauth2/token grant_type=authorization_code&code=...&code_verifier=...
- 7Aero2 → Your AppReturn access_token, id_token, refresh_tokenRS256-signed JWTs
- 8Your App → Aero2Fetch user info (optional)GET /oauth2/userinfo Authorization: Bearer <access_token>
Step by Step
Generate PKCE Values
Your application generates a random code_verifier and computes its SHA-256 hash as the code_challenge.
// Generate code_verifier (43-128 characters, URL-safe)
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const codeVerifier = base64UrlEncode(array);
// Compute code_challenge = SHA-256(code_verifier)
const hash = await crypto.subtle.digest(
'SHA-256',
new TextEncoder().encode(codeVerifier)
);
const codeChallenge = base64UrlEncode(hash);Try it yourself:
PKCE Generator
Redirect to Authorize
Redirect the user to Aero2's authorization endpoint with your client details and the code challenge:
GET https://aero2.dev/oauth2/authorize
?client_id=your-client-id
&redirect_uri=https://yourapp.com/callback
&response_type=code
&scope=openid profile email
&state=random-csrf-token
&code_challenge=<code_challenge>
&code_challenge_method=S256
&nonce=random-nonceUser Authenticates
Aero2 presents the login page. The user signs in with their identity provider (e.g., GitHub).
Receive Authorization Code
After authentication, Aero2 redirects back to your redirect_uri with a short-lived authorization code:
https://yourapp.com/callback?code=abc123&state=random-csrf-tokenExchange Code for Tokens
Your server exchanges the code for tokens at the token endpoint:
curl -X POST https://aero2.dev/oauth2/token \
-d "grant_type=authorization_code" \
-d "code=abc123" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "client_id=your-client-id" \
-d "client_secret=your-client-secret" \
-d "code_verifier=<original_code_verifier>"Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "dGhpcyBpcyBh...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile email"
}Use the Access Token
Use the access token to call protected APIs:
curl https://aero2.dev/oauth2/userinfo \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."Why PKCE?
Without PKCE, a malicious app could intercept the authorization code during the redirect and exchange it for tokens. PKCE prevents this by binding the code to the original requester:
- Only the app that generated the
code_verifiercan compute the matchingcode_challenge - The code can only be exchanged by presenting the original
code_verifier - An interceptor without the
code_verifiercannot exchange the code
Aero2 only supports S256 (SHA-256) — the plain method is not allowed.