PKCE Extension — Securing Authorization Code for Public OAuth2 Clients
In this tutorial, you will learn about PKCE Extension. We cover key concepts, practical examples, and best practices to help you master this topic.
PKCE (Proof Key for Code Exchange, pronounced "pixie") extends the Authorization Code flow with a cryptographic challenge that prevents interception attacks on public clients.
What You'll Learn
How PKCE works, the code verifier and challenge, implementation for mobile apps and SPAs, and why it replaces the client secret.
Why It Matters
Mobile apps and SPAs cannot keep a client secret. PKCE provides equivalent security through a single-use cryptographic proof. It is now recommended for ALL OAuth2 clients, not just public ones.
Real-World Use
Auth0 uses PKCE by default. Google supports PKCE for mobile and SPA OAuth2. Any app using modern "Login with Google" on mobile uses PKCE.
sequenceDiagram
participant App as Public Client
participant Auth as Authorization Server
App->>App: Generate code_verifier
App->>App: SHA256(verifier) = code_challenge
App->>Auth: /auth?code_challenge=xyz&method=S256
Auth->>App: Authorization Code
App->>Auth: POST /token + code_verifier
Auth->>Auth: SHA256(verifier) == challenge?
Auth->>App: Access Token (if match)
Code Example: PKCE Flow
import requests, hashlib, base64, secrets
def generate_pkce_pair():
code_verifier = secrets.token_urlsafe(64)[:128]
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b"=").decode()
return code_verifier, code_challenge
code_verifier, code_challenge = generate_pkce_pair()
# Step 1: Authorization request
auth_params = {
"response_type": "code",
"client_id": "public-client",
"redirect_uri": "myapp://callback",
"code_challenge": code_challenge,
"code_challenge_method": "S256",
"state": secrets.token_urlsafe(32)
}
# Step 2: Exchange code (in callback)
token_response = requests.post("https://auth.example.com/token", data={
"grant_type": "authorization_code",
"code": "code-from-redirect",
"redirect_uri": "myapp://callback",
"client_id": "public-client",
"code_verifier": code_verifier
})
Common Mistakes
1. Short or Predictable Verifier
Must be 43-128 characters of unreserved URL characters. Use secrets.token_urlsafe(64).
2. Not Stripping Base64 Padding
The code challenge must have = padding stripped.
3. Forgetting to Store the Verifier
The verifier must be stored on the client until the redirect arrives.
4. Using PKCE Without State
PKCE prevents code interception, not CSRF. Always use state parameter too.
5. Using Plain Method Instead of S256
Only use plain if the auth server does not support S256.
Practice Questions
- What does PKCE stand for?
- What is the difference between verifier and challenge?
- Why can't mobile apps use Authorization Code without PKCE?
- What is code_challenge_method S256?
- Does PKCE replace the state parameter?
Answers:
- Proof Key for Code Exchange — prevents authorization code interception.
- Verifier is the random secret. Challenge is the transformed (SHA256-hashed) version sent in the auth request.
- Mobile apps cannot keep a client secret. PKCE provides security without it.
- S256 means SHA-256 hashing of the verifier. Plain sends the verifier directly (less secure).
- No. PKCE prevents code interception. State prevents CSRF. Both are needed.
Challenge: Implement a full PKCE flow for a mobile app or SPA with verifier generation, challenge computation, code exchange, and error handling.
FAQ
Mini Project
Build a Python script demonstrating the full PKCE flow: generate verifier and challenge, construct the auth URL, exchange the code, and verify the tokens.
What's Next
Now learn about OAuth2 Redirect URIs — the security-critical configuration for OAuth2 callbacks.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro