PKCE (Proof Key for Code Exchange)
Understanding PKCE and how it enhances OAuth security.
What is PKCE?
PKCE (Proof Key for Code Exchange) is a security extension to OAuth 2.0 that prevents authorization code interception attacks. It's especially important for public clients (mobile apps, SPAs) but is also recommended for confidential clients.
How PKCE Works
Step 1: Generate Code Verifier
A random, cryptographically random string is generated:
import secrets
import base64
code_verifier = base64.urlsafe_b64encode(
secrets.token_bytes(32)
).decode('utf-8').rstrip('=')
Step 2: Generate Code Challenge
The code verifier is hashed using SHA256:
import hashlib
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
Step 3: Authorization Request
The code challenge is sent in the authorization request:
GET /oauth/authorize?
client_id=...
&redirect_uri=...
&code_challenge={code_challenge}
&code_challenge_method=S256
Step 4: Token Exchange
The code verifier is sent in the token exchange:
POST /oauth/token
{
"grant_type": "authorization_code",
"code": "...",
"code_verifier": "{code_verifier}",
...
}
Step 5: Verification
The provider verifies:
computed_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
if computed_challenge != stored_challenge:
raise InvalidCodeVerifier()
Automatic PKCE
The sva-oauth-client package automatically implements PKCE:
from sva_oauth_client.client import SVAOAuthClient
client = SVAOAuthClient(...)
# PKCE is automatically handled
auth_url, code_verifier = client.get_authorization_url()
# code_verifier is stored in session
# code_challenge is included in auth_url
Security Benefits
Prevents Code Interception
Without PKCE:
- Attacker intercepts authorization code
- Attacker exchanges code for tokens
- Attacker gains access
With PKCE:
- Attacker intercepts authorization code
- Attacker doesn't have code verifier
- Attacker cannot exchange code
- Attack fails
Protects Public Clients
PKCE is especially important for:
- Mobile applications
- Single-page applications (SPAs)
- Desktop applications
Defense in Depth
Even for confidential clients, PKCE provides:
- Additional security layer
- Protection against compromised secrets
- Better security posture
Implementation Details
Code Verifier Requirements
- Length: 43-128 characters
- Character set: A-Z, a-z, 0-9, -, ., _, ~
- Randomness: Cryptographically random
Code Challenge Method
SVA OAuth supports:
S256- SHA256 (recommended)plain- Plain text (not recommended)
Storage
The code verifier is stored:
- In session (server-side)
- Temporarily in localStorage (client-side, for callback)
- Never exposed to user
Best Practices
- Always use PKCE - Even for confidential clients
- Use S256 - SHA256 method is more secure
- Store securely - Code verifier in server-side session
- Clear after use - Remove code verifier after token exchange
- Don't reuse - Generate new verifier for each flow
Verification
Manual Verification
You can verify PKCE is working:
from sva_oauth_client.client import SVAOAuthClient
client = SVAOAuthClient(...)
auth_url, code_verifier = client.get_authorization_url()
# Check auth_url contains code_challenge
assert 'code_challenge' in auth_url
assert 'code_challenge_method=S256' in auth_url
# Verify code_verifier is generated
assert code_verifier is not None
assert len(code_verifier) >= 43
Next Steps
- Learn about CSRF Protection
- Understand Data Token Verification
- Read Security Best Practices