💡Single Sign On

PKCE - The new standard

PKCE (Proof Key for Code Exchange) Implementation

PKCE (pronounced "pixy") is an OAuth 2.0 security extension designed to protect authorization code flow against authorization code interception attacks. It was originally developed for mobile applications but is now recommended for all clients that cannot maintain client secrecy.

Benefits Over Traditional Authorization Code and Implicit Grant

  • Enhanced Security for Public Clients: Unlike traditional authorization code flow which relies on client secrets, PKCE uses dynamically created secrets, making it suitable for applications where client secrets cannot be securely stored (mobile apps, SPAs).

  • Protection Against Code Interception: PKCE prevents attackers from intercepting authorization codes and exchanging them for tokens, as the code verifier is required during token exchange.

  • Superior to Implicit Grant: PKCE eliminates the security risks of implicit grant flow where access tokens were returned directly in the URL fragment, vulnerable to browser history and referrer header leaks.

  • No Client Secret Requirement: Removes the need for hard-coded client secrets in applications where they cannot be protected, reducing attack surface.

  • Prevents Authorization Code Injection: The code verifier binding prevents attackers from injecting stolen authorization codes from other sessions.

PKCE Full Flow

Step 1: Code Verifier and Challenge Creation

  • Client generates a cryptographically random code_verifier (43-128 characters, using A-Z, a-z, 0-9, -, ., _, ~)

  • Client creates code_challenge by hashing code_verifier with SHA-256 and base64url encoding

  • Client stores code_verifier securely for later use

Step 2: Authorization Request

  • Client redirects user to authorization endpoint with:

    • response_type=code

    • client_id

    • redirect_uri

    • code_challenge

    • code_challenge_method=S256

    • state (CSRF protection)

Step 3: User Authentication and Consent

  • User authenticates and grants consent at authorization server

  • Authorization server stores code_challenge associated with the authorization code

Step 4: Authorization Response

  • Authorization server redirects to client's redirect_uri with:

    • authorization code

    • state (must match request state)

Step 5: Token Request

  • Client makes POST request to token endpoint with:

    • grant_type=authorization_code

    • code (authorization code received)

    • redirect_uri (must match initial request)

    • client_id

    • code_verifier (original random value)

Step 6: Token Response

  • Authorization server:

    • Hashes code_verifier using SHA-256 and compares with stored code_challenge

    • If match is successful, issues access token and optionally refresh token

    • Returns tokens to client

Security Considerations

  • Code Verifier Entropy: Must be cryptographically random with sufficient length (recommended 32+ bytes)

  • Code Verifier Storage: Must be protected in client storage and not exposed in logs or URLs

  • TLS Mandatory: All communications must use HTTPS to prevent interception

  • Challenge Method: S256 (SHA-256) is strongly preferred over plain method

  • State Parameter: Must still be used for CSRF protection alongside PKCE

  • Token Storage: Received tokens must be stored securely on client side

  • Short Authorization Code Lifetime: Authorization codes should expire quickly (recommended 10 minutes or less)

Best Supported Application Types

  • Native Mobile Applications: Primary use case where client secrets cannot be protected

  • Single Page Applications (SPAs): JavaScript applications running in browser

  • Desktop Applications: Installed applications where client secret protection is difficult

  • Progressive Web Apps (PWAs): Web applications with app-like functionality

  • CLI Tools: Command-line applications requiring user authentication

  • IoT Devices: Devices with limited security capabilities

Sample Implementation Code Snippets

Generating Code Verifier and Challenge (JavaScript):

  • // Generate random code_verifier const generateCodeVerifier = () => { const array = new Uint8Array(32); crypto.getRandomValues(array); return base64url.encode(array); }

  • // Create code_challenge const createCodeChallenge = async (verifier) => { const encoder = new TextEncoder(); const data = encoder.encode(verifier); const digest = await crypto.subtle.digest('SHA-256', data); return base64url.encode(new Uint8Array(digest)); }

Conclusion

PKCE provides a robust security enhancement to the OAuth 2.0 authorization code flow, particularly for public clients that cannot maintain client secrecy. By adding the code verifier/challenge mechanism, it effectively prevents authorization code interception attacks while maintaining the benefits of the authorization code flow. Its adoption is now considered a best practice for mobile applications, SPAs, and other public clients, and is recommended by security standards such as OAuth 2.0 Security Best Current Practice and OpenID Connect.

Comments

to like and join the conversation.