Back to Grant Types
Recommended StandardID: pkce

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.

#oauth2#pkce#authorization-code#oidc#spa#mobile#desktop#security

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

Sequence Diagram
Interactive Diagram
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 Resource

Step-by-Step Flow Breakdown

Detailed breakdown of every message exchange, query parameter, and HTTP payload

1

User Clicks Login

User→Client App (SPA / Mobile)

The user clicks the login button in the client application (SPA, iOS/Android app, or desktop app).

2

Generate PKCE Verifier & Challenge

Client App (SPA / Mobile)→Client App (SPA / Mobile)

The client application generates a cryptographically random code_verifier (between 43 and 128 characters) and computes the code_challenge using BASE64URL(SHA256(code_verifier)).

PKCE Generation Code
// Generate a cryptographically secure random verifier
const codeVerifier = generateRandomString(64);

// Compute code_challenge = Base64URL(SHA-256(codeVerifier))
const codeChallenge = base64Url(sha256(codeVerifier));
3

Authorization Request with PKCE Challenge

Client App (SPA / Mobile)→Authorization Server

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.

Authorization Request with PKCE
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.com
4

Authenticate and Grant Consent

Authorization Server→User

The authorization server prompts the user to authenticate and confirm permission for requested scopes.

5

Return Authorization Code

Authorization Server→Client App (SPA / Mobile)

The authorization server records the code_challenge and redirects back to the redirect URI with the short-lived authorization code.

Redirect with Authorization Code
HTTP/1.1 302 Found
Location: https://myapp.com/callback?
    code=SplxlOBeZQQYbYS6WxSbIA
    &state=af0ifjsldkj
6

Token Exchange with Code Verifier

Client App (SPA / Mobile)→Authorization Server

The client application calls the token endpoint with the authorization code and original unhashed code_verifier. For public clients, no client secret is required.

Token Request with code_verifier
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%2Fcallback
7

Verify Challenge and Issue Tokens

Authorization Server→Client App (SPA / Mobile)

The authorization server computes SHA256 on the received code_verifier and matches it against the stored code_challenge. If valid, tokens are issued.

Token Response
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..."
}
8

Access Protected Resources

Client App (SPA / Mobile)→Resource Server (API)

The client makes authenticated API calls passing the access token in the HTTP Authorization header.

Authenticated Request
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

Client Templates using this Grant Type

Explore ready-to-use client configurations supporting PKCE

All templates

Other OAuth 2.0 Grant Types

Compare with other authentication and authorization flows