Authorization Code Flow with PKCE
The modern standard login flow recommended for Single Page Apps (SPAs), Mobile apps, and Native clients, mitigating authorization code interception and injection attacks.
Overview
Proof Key for Code Exchange (PKCE, RFC 7636) is an extension to the Authorization Code flow originally designed to secure public clients (such as Single Page Applications and Mobile apps) that cannot safely maintain a client secret.
Before redirecting the user to authenticate, the client generates a cryptographically random string known as the code_verifier, and derives a cryptographic hash known as the code_challenge (using SHA-256). The code_challenge is passed in the initial authorization request.
When redeeming the authorization code at the token endpoint, the client presents the unhashed code_verifier. The authorization server hashes the verifier and ensures it matches the original challenge. If an attacker intercepts the authorization code in transit, they cannot redeem it without knowing the secret code_verifier.
Under the OAuth 2.1 specification, PKCE is required for all OAuth 2.0 clients, establishing it as the modern universal standard for user authentication.
Quick Specifications
- Flow Status
- recommended
- Recommended For
- SPA (Single Page Application)Mobile ApplicationDesktop ApplicationCLIWeb Application
- Token Auth Methods
- NoneClient Secret BasicClient Secret Post
- Primary Standard
- RFC 7636
Sequence Diagram
Visual sequence illustrating entity interactions and protocol steps
sequenceDiagram
autonumber
actor U as User
participant C as Client App (SPA / Mobile)
participant AS as Authorization Server
participant RS as Resource Server (API)
U->>C: Click "Log In"
C->>C: Generate high-entropy code_verifier
C->>C: Derive code_challenge = BASE64URL(SHA256(code_verifier))
C->>AS: Redirect to /authorize (response_type=code, code_challenge, code_challenge_method=S256, state)
AS->>U: Display Login & Consent Prompt
U->>AS: Submit Credentials & Consent
AS-->>C: Redirect to redirect_uri with ?code=AUTH_CODE&state=STATE
C->>AS: POST /oauth/token (grant_type=authorization_code, code, code_verifier, client_id, redirect_uri)
AS->>AS: Verify SHA256(code_verifier) == stored code_challenge
AS-->>C: 200 OK (access_token, id_token, refresh_token)
C->>RS: Request Data (Authorization: Bearer ACCESS_TOKEN)
RS-->>C: 200 OK Protected ResourceStep-by-Step Flow Breakdown
Detailed breakdown of every message exchange, query parameter, and HTTP payload
User Clicks Login
The user clicks the login button in the client application (SPA, iOS/Android app, or desktop app).
Generate PKCE Verifier & Challenge
The client application generates a cryptographically random code_verifier (between 43 and 128 characters) and computes the code_challenge using BASE64URL(SHA256(code_verifier)).
// Generate a cryptographically secure random verifier
const codeVerifier = generateRandomString(64);
// Compute code_challenge = Base64URL(SHA-256(codeVerifier))
const codeChallenge = base64Url(sha256(codeVerifier));Authorization Request with PKCE Challenge
The client redirects the browser or opens an in-app browser tab to the authorization endpoint, sending the code_challenge and code_challenge_method=S256.
GET /authorize?
response_type=code
&client_id=a4uFTLz6HjGRA8LM2opHBzcKHhCXFtMk8
&redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback
&scope=openid%20profile%20email
&state=af0ifjsldkj
&code_challenge=qjrzSW9gMiUgpUvqgEPE4_-8swvyCtfOVvg55o5S_es
&code_challenge_method=S256 HTTP/1.1
Host: login.auth.comAuthenticate and Grant Consent
The authorization server prompts the user to authenticate and confirm permission for requested scopes.
Return Authorization Code
The authorization server records the code_challenge and redirects back to the redirect URI with the short-lived authorization code.
HTTP/1.1 302 Found
Location: https://myapp.com/callback?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkjToken Exchange with Code Verifier
The client application calls the token endpoint with the authorization code and original unhashed code_verifier. For public clients, no client secret is required.
POST /oauth/token HTTP/1.1
Host: login.auth.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=a4uFTLz6HjGRA8LM2opHBzcKHhCXFtMk8
&code=SplxlOBeZQQYbYS6WxSbIA
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
&redirect_uri=https%3A%2F%2Fmyapp.com%2FcallbackVerify Challenge and Issue Tokens
The authorization server computes SHA256 on the received code_verifier and matches it against the stored code_challenge. If valid, tokens are issued.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rF4k91Z3lK...",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE2In0..."
}Access Protected Resources
The client makes authenticated API calls passing the access token in the HTTP Authorization header.
GET /api/v1/user HTTP/1.1
Host: api.myapp.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...Security Considerations
Critical safeguards, threat mitigations, and implementation best practices
Always use S256 (Never "plain")
RFC 7636 allows plain text code_challenge_method="plain" only if the client cannot perform SHA-256. Plain PKCE offers no protection against passive eavesdropping. Always enforce code_challenge_method="S256".
High-Entropy Verifier
The code_verifier must use unguessable cryptographic random bytes with at least 256 bits of entropy (between 43 and 128 ASCII characters).
Replace Implicit Flow
Authorization Code with PKCE completely supersedes the deprecated Implicit flow for SPAs and mobile apps. Access tokens should never be exposed in URL fragments.
Refresh Token Rotation
When issuing refresh tokens to public clients, authorization servers must enforce Refresh Token Rotation to detect and mitigate token theft.
Specifications & Standards
Official IETF RFCs and OpenID Foundation standards defining this flow
Proof Key for Code Exchange by OAuth Public Clients
Defines the code_verifier, code_challenge, and S256 verification rules preventing code interception attacks.
OAuth 2.0 for Native Apps (BCP)
Best practices for implementing PKCE in mobile, desktop, and native applications using system browsers.
The OAuth 2.1 Authorization Framework
Mandates PKCE for all authorization code flows across confidential and public clients.
Client Templates using this Grant Type
Explore ready-to-use client configurations supporting PKCE
Other OAuth 2.0 Grant Types
Compare with other authentication and authorization flows