OAuth 2.0 — Authorization Code + PKCE
The foundational OAuth 2.0 grant type for delegated user authorization. A client redirects the user to an Authorization Server, which authenticates the user and issues a short-lived authorization code. The client exchanges the code for tokens. PKCE (Proof Key for Code Exchange, RFC 7636) is layered on top to prevent authorization code interception attacks — mandatory for public clients and best practice for all.
The user clicks 'Sign In'. Before redirecting, the client generates a PKCE code_verifier (random secret) and derives a code_challenge via SHA-256. It redirects the browser to the AS /authorize endpoint embedding the challenge and a CSRF-guard state value.
• RFC 7636 §4.1: code_verifier must be 43–128 URL-safe chars from a cryptographically secure source.
• RFC 7636 §4.2: S256 is the required method (plain is only allowed if S256 is not feasible). code_challenge = BASE64URL(SHA-256(ASCII(code_verifier))).
• RFC 6749 §10.12: The state parameter prevents CSRF — the client must generate it randomly and verify the AS echoes it back unchanged.
• response_type=code requests an authorization code; the client will exchange the code for tokens in a back-channel request (step 5), keeping tokens out of the browser.
Step 1: GET / (Sign In clicked)
text/html
Construction Steps
code_verifier = high-entropy random string = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" Must be 43–128 characters from the unreserved alphabet: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~" Generate using a cryptographically secure RNG (e.g., SecureRandom, crypto.getRandomValues). The value is stored server-side or in a secure session — NEVER sent until the token request.
code_challenge = BASE64URL(SHA-256(ASCII(code_verifier))) input : "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" SHA-256: 0xC481... (32 bytes) BASE64URL(…): "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM" The challenge is safe to embed in the authorization URL because SHA-256 is not reversible — an observer cannot recover the code_verifier from the challenge.
Client stores server-side (encrypted cookie or session): state : "xyzABC123" → returned verbatim by AS (CSRF guard) code_verifier : "dBjftJeZ4CVP..." → revealed only at token endpoint The authorization URL carries: code_challenge = E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM code_challenge_method = S256 The AS records the challenge and will verify it when the authorization code is exchanged.
Signature Base String
code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Signing Key
Client-generated cryptographically random value (43–128 URL-safe chars)Signature Output
code_challenge = E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM