Skip to main content

PKCE

Proof Key for Code Exchange (RFC 7636) defends the authorization code grant against code interception. The client picks a high-entropy secret (code_verifier), sends only its SHA-256 hash (code_challenge) with the authorization request, and supplies the original verifier when redeeming the code at the token endpoint. ThunderID rejects the exchange unless the hashes match.

OAuth 2.1 makes PKCE mandatory for public clients and recommends it for every authorization code flow. ThunderID follows this baseline.

How It Works

How ThunderID Implements It
AspectBehavior
Supported challenge methodsS256 only: plain is rejected with invalid_request
Public clientsPKCE is mandatory for public clients (token_endpoint_auth_method=none)
Confidential clientspkceRequired defaults to false but can be enabled per application
Verifier rules43 to 128 characters; ASCII unreserved set per RFC 7636 §4.1
Challenge encodingBase64url-encoded SHA-256 of the verifier; 43 characters; no padding
StorageThe challenge is bound to the issued authorization code; the code is single-use
Interaction with PARThe code_challenge is supplied at PAR push time; it cannot be added or changed at the /oauth2/authorize redirect
Failure modeMissing verifier, wrong verifier, or mismatched challenge → invalid_grant at the token endpoint

Try It in ThunderID

  1. Open Applications or Agents in the ThunderID Console and select your client.
  2. Open the Advanced Settings tab.
  3. Toggle Require PKCE on for confidential clients (already on for public clients).
  4. Save.

Generate the Verifier and Challenge

// Browser / Node
function base64url(buf) {
return btoa(String.fromCharCode(...new Uint8Array(buf)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

const verifierBytes = crypto.getRandomValues(new Uint8Array(64));
const code_verifier = base64url(verifierBytes);

const hash = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(code_verifier));
const code_challenge = base64url(hash);

Send code_challenge on the authorization request:

GET /oauth2/authorize
?response_type=code
&client_id=$CLIENT_ID
&redirect_uri=https://app.example.com/callback
&scope=openid%20profile
&state=xyz
&code_challenge=$CODE_CHALLENGE
&code_challenge_method=S256

Send code_verifier on the token exchange:

curl -X POST https://thunderid.example.com/oauth2/token \
-d "grant_type=authorization_code" \
-d "code=$CODE" \
-d "redirect_uri=https://app.example.com/callback" \
-d "client_id=$CLIENT_ID" \
-d "code_verifier=$CODE_VERIFIER"

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.