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

PKCE is enabled by default in every OAuth42 SDK — the SDK generates the code_verifier, computes the S256 code_challenge, stores the verifier in the session, and sends it on code exchange. You do not need to write PKCE primitives yourself.

  • Next.js (@oauth42/next): PKCE is configured in the OAuth42 provider — nothing to enable. See the tutorial.
  • Other JS/TS (openid-client / oidc-client-ts): both libraries do PKCE by default. See JavaScript SDK page.
  • Python: OAuth42Client.create_authorization_url() returns the verifier; the Flask/FastAPI middleware handles the whole flow end-to-end. See Python SDK page.
  • Rust: SessionManager and TokenCache handle PKCE inside the authorization-code grant. See Rust SDK page.

If you really must do it by hand

The two primitives, for reference:

// Node.js
import crypto from 'crypto';

const codeVerifier = crypto.randomBytes(64).toString('base64url');
const codeChallenge = crypto
  .createHash('sha256')
  .update(codeVerifier)
  .digest('base64url');

// Send code_challenge + code_challenge_method=S256 on /authorize,
// then code_verifier on /token.

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.