Back to Documentation

PKCE Implementation

Proof Key for Code Exchange (PKCE) is an extension to the OAuth 2.0 authorization code flow that prevents authorization code interception attacks.

What is PKCE?

PKCE (pronounced "pixie") is a security extension for OAuth 2.0 public clients on mobile devices and single-page applications (SPAs) performing the Authorization Code grant. It prevents several attacks and is now recommended for all OAuth 2.0 clients, including confidential clients.

PKCE was originally designed to protect mobile apps, but it's now considered a best practice for all OAuth 2.0 authorization code flows. OAuth42 requires PKCE for all authorization code grants.

Security Requirement

OAuth42 enforces PKCE for all authorization code flows. Requests without valid PKCE parameters will be rejected.

How PKCE Works

PKCE introduces two new parameters to the authorization code flow:

1

Generate Code Verifier

The client creates a cryptographically random string called the code_verifier. This should be a high-entropy random string between 43-128 characters.

// Generate a random code verifier
const codeVerifier = generateRandomString(128);

// Example output:
// "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
2

Create Code Challenge

The client creates a code_challenge by hashing the code verifier with SHA-256 and base64url-encoding the result.

// Create code challenge from verifier
const codeChallenge = base64urlEncode(
  sha256(codeVerifier)
);

// Example output:
// "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
3

Send Authorization Request

The client includes the code challenge and challenge method in the authorization request.

GET /oauth/authorize?
  response_type=code&
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://yourapp.com/callback&
  scope=openid+profile+email&
  state=random_state&
  code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
  code_challenge_method=S256
4

Exchange Code with Verifier

When exchanging the authorization code for tokens, the client includes the original code verifier.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=https://yourapp.com/callback&
client_id=YOUR_CLIENT_ID&
code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
5

Server Validates

OAuth42 hashes the code verifier and compares it to the stored code challenge. If they match, tokens are issued.

Validation:

sha256(code_verifier) === stored_code_challenge

Why PKCE is Important

Prevents Authorization Code Interception

Without PKCE, if an attacker intercepts the authorization code (e.g., through a malicious app on the same device), they can exchange it for tokens. PKCE prevents this because the attacker doesn't have the code verifier.

No Client Secret Needed

PKCE allows public clients (mobile apps, SPAs) to securely use the authorization code flow without needing to store a client secret, which can't be kept secure in these environments.

Defense in Depth

Even for confidential clients that use a client secret, PKCE provides an additional layer of security against sophisticated attacks.

Implementation Examples

JavaScript/TypeScript

import { OAuth42Client } from '@oauth42/sdk';

// SDK handles PKCE automatically
const oauth42 = new OAuth42Client({
  clientId: 'your_client_id',
  redirectUri: 'http://localhost:3000/callback',
  issuer: 'https://auth.oauth42.com',
});

// Generate PKCE parameters
const { codeVerifier, codeChallenge } = await oauth42.generatePKCE();

// Store code verifier securely (e.g., session)
session.codeVerifier = codeVerifier;

// Create authorization URL with code challenge
const authUrl = oauth42.getAuthorizationUrl({
  state: 'random_state',
  codeChallenge,
  codeChallengeMethod: 'S256',
});

// Redirect user
window.location.href = authUrl;

Python

from oauth42_sdk import OAuth42Client

# SDK handles PKCE automatically
oauth42 = OAuth42Client(
    client_id='your_client_id',
    redirect_uri='http://localhost:8000/callback',
    issuer='https://auth.oauth42.com',
)

# Generate PKCE parameters
code_verifier, code_challenge = oauth42.generate_pkce()

# Store code verifier securely (e.g., session)
session['code_verifier'] = code_verifier

# Create authorization URL with code challenge
auth_url = oauth42.get_authorization_url(
    state='random_state',
    code_challenge=code_challenge,
    code_challenge_method='S256'
)

# Redirect user
return redirect(auth_url)

Manual Implementation (Node.js)

import crypto from 'crypto';

function generateCodeVerifier() {
  return crypto.randomBytes(64).toString('base64url');
}

function generateCodeChallenge(verifier) {
  return crypto
    .createHash('sha256')
    .update(verifier)
    .digest('base64url');
}

// Usage
const codeVerifier = generateCodeVerifier();
const codeChallenge = generateCodeChallenge(codeVerifier);

console.log('Code Verifier:', codeVerifier);
console.log('Code Challenge:', codeChallenge);

Best Practices

Always Use S256

Always use S256 as the code challenge method. The plain method is deprecated and insecure.

Use Sufficient Entropy

Generate code verifiers with at least 43 characters of high-entropy random data. Use cryptographically secure random number generators.

Store Code Verifier Securely

Store the code verifier securely between the authorization request and token exchange. Use secure session storage on the server, not client-side storage.

Use SDKs When Possible

OAuth42's official SDKs handle PKCE implementation correctly and securely. Use them instead of implementing PKCE manually unless you have specific requirements.