Skip to content

PKCE Extension — Securing Authorization Code for Public OAuth2 Clients

DodaTech Updated 2026-06-28 3 min read

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

  1. What does PKCE stand for?
  2. What is the difference between verifier and challenge?
  3. Why can't mobile apps use Authorization Code without PKCE?
  4. What is code_challenge_method S256?
  5. Does PKCE replace the state parameter?

Answers:

  1. Proof Key for Code Exchange — prevents authorization code interception.
  2. Verifier is the random secret. Challenge is the transformed (SHA256-hashed) version sent in the auth request.
  3. Mobile apps cannot keep a client secret. PKCE provides security without it.
  4. S256 means SHA-256 hashing of the verifier. Plain sends the verifier directly (less secure).
  5. 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

Why is PKCE called 'pixie'?

The original authors pronounced it 'pixie'. Both 'pixie' and 'P-K-C-E' are accepted.

Can PKCE be used with confidential clients?

Yes. PKCE is recommended for ALL clients, even confidential ones. Defense in depth.

What happens if the verifier doesn't match?

The token endpoint returns invalid_grant. The auth server computed SHA256(verifier) and it didn't match the challenge from the auth request.

Is PKCE vulnerable to man-in-the-middle?

PKCE protects the token exchange. HTTPS protects the entire flow. HTTPS + PKCE + state = well-protected.

Does PKCE work with all OAuth2 providers?

Most modern providers support PKCE. Check their documentation. OAuth2.1 requires PKCE for all clients.

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