OAuth 2.0 is a widely used authorization framework that allows applications to obtain limited access to user resources without handling user credentials directly. The Authorization Code Flow with PKCE (Proof Key for Code Exchange) is a security-enhanced version of the Authorization Code Flow, specifically designed to address vulnerabilities in public clients like mobile apps and single-page applications (SPAs) that cannot safely store a client secret.

Why PKCE Is Needed

Traditional Authorization Code Flow relies on a client_secret to authenticate the client when exchanging an authorization code for a token. In public clients (like browser apps or mobile apps), this secret cannot be safely stored. Without proper safeguards, attackers could intercept the authorization code during redirection and exchange it for tokens.

PKCE mitigates this threat by introducing a one-time verification mechanism between the client and the authorization server that does not rely on a client secret, making the flow secure for public clients.

How Authorization Code Flow with PKCE Works

Here’s a step-by-step breakdown of the process:

1. Client Generates a Code Verifier and Code Challenge

  • The code verifier is a cryptographically random string (43–128 characters).
  • The code challenge is derived by applying a SHA256 hash (or using plain) to the code verifier and base64-url encoding the result.
code_verifier = "randomly_generated_string"
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))

2. Client Initiates Authorization Request

The client redirects the user to the authorization server’s /authorize endpoint with the following parameters:

  • response_type=code
  • client_id
  • redirect_uri
  • scope
  • code_challenge
  • code_challenge_method=S256
GET /authorize?
  response_type=code&
  client_id=your-client-id&
  redirect_uri=https://app.com/callback&
  scope=openid profile email&
  code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
  code_challenge_method=S256

3. User Authenticates and Grants Access

The user logs in and approves the authorization request. The authorization server redirects back to the redirect_uri with an authorization code.

4. Client Sends Token Request

The client then sends a POST request to the /token endpoint including:

  • grant_type=authorization_code
  • code (received in step 3)
  • redirect_uri (must match original)
  • client_id
  • code_verifier
POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=SplxlOBeZQQYbYS6WxSbIA&
redirect_uri=https://app.com/callback&
client_id=your-client-id&
code_verifier=randomly_generated_string

5. Authorization Server Validates Code Verifier

The server hashes the code_verifier and compares it to the original code_challenge. If they match, it returns:

  • access_token
  • id_token (if OpenID Connect is used)
  • refresh_token (if applicable)

6. Client Uses Access Token

The client includes the access_token in the Authorization: Bearer header to access protected resources.


Security Advantages of PKCE

  • Protects against authorization code interception
  • Eliminates reliance on client secrets for public clients
  • Recommended by the OAuth 2.1 draft for all client types

When to Use PKCE

  • Mobile applications (iOS, Android)
  • Single-page applications (SPA)
  • Any client that cannot securely store a client_secret

Conclusion

The Authorization Code Flow with PKCE represents a modern, secure way for public clients to participate in OAuth 2.0. By binding the authorization code to a dynamically generated key pair, PKCE eliminates a major vulnerability and strengthens trust in user authorization without requiring secret storage. As OAuth continues to evolve, PKCE is considered a best practice and should be the default choice for native and browser-based applications.