Skip to content

PKCE Flow Mechanics

The PKCE (Proof Key for Code Exchange) flow is a critical enhancement to the OAuth 2.0 authorization code flow, specifically designed to secure public clients (e.g., mobile apps, single-page applications) that cannot securely store client secrets. By introducing the code verifier and code challenge mechanisms, PKCE mitigates the risk of authorization code interception and replay attacks, ensuring that only the legitimate client can exchange the authorization code for access tokens.


Code Verifier and Code Challenge

Code Verifier

The code verifier is a cryptographically random string (typically 43–128 characters) generated by the client. It serves as a secret key used to derive the code challenge. The verifier is stored temporarily by the client and is never sent to the authorization server.

Example (Python):

import os
import base64

# Generate a 43-character code verifier
code_verifier = base64.urlsafe_b64encode(os.urandom(32)).decode('utf-8').rstrip('=')
print("Code Verifier:", code_verifier)

Code Challenge

The code challenge is a hashed version of the code verifier, encoded in base64 URL-safe format. It is sent to the authorization server during the authorize request. The hash function (e.g., SHA256) and encoding method are agreed upon in advance (typically SHA256 and URL-safe base64).

Example (Python):

import hashlib

# Derive the code challenge from the code verifier
code_challenge = hashlib.sha256(code_verifier.encode('utf-8')).digest()
code_challenge = base64.urlsafe_b6.4encode(code_challenge).decode('utf-8').rstrip('=')
print("Code Challenge:", code_challenge)


PKCE Flow Mechanics

1. Client Redirects User to Authorization Server

The client generates a code verifier and code challenge, then redirects the user to the authorization server with: - code_challenge (as derived above) - code_challenge_method (e.g., S256 for SHA256) - Other standard parameters (e.g., client_id, redirect_uri, scope)

Example Request:

GET https://auth.example.com/authorize?
client_id=client123
&redirect_uri=https://app.example.com/callback
&response_type=code
&scope=openid
&code_challenge=xyzABC123
&code_challenge_method=S256

The user authenticates and approves the request. The authorization server issues an authorization code (not directly usable as a token) and redirects the user back to the client’s redirect_uri.

3. Client Exchanges Code for Tokens

The client sends the authorization code and the original code verifier to the token endpoint to exchange for tokens: - code (from the authorization response) - code_verifier (stored earlier)

Example Request:

POST https://auth.example.com/token
client_id=client123
&client_secret=secret456
&code=auth_code
&grant_type=authorization_code
&code_verifier=abcXYZ789

The authorization server verifies the code challenge (derived from the code verifier) matches the stored value. If valid, it issues access tokens and ID tokens.


Diagram: PKCE Flow Overview

[Client] → Generate code_verifier → Derive code_challenge → Redirect to Auth Server
                                         ↓
[User] → Authenticate → Grant Consent → Auth Server issues authorization_code → Redirect to Client
                                         ↓
Client → Send code + code_verifier to Token Endpoint → Auth Server validates code_challenge → Issue Tokens

Key Takeaways

  • PKCE prevents authorization code interception by requiring a cryptographic proof (code verifier) during token exchange.
  • The code challenge is a hashed version of the code verifier, ensuring the client is the only entity with the original secret.
  • Public clients (e.g., mobile apps) rely on PKCE to securely obtain tokens without storing secrets.
  • Always use SHA256 and URL-safe base64 for code challenge generation, as defined in RFC 7636.