Digital Toolkit

Proof Key for Code Exchange (PKCE)

Authentication Framework > Overview > Proof Key for Code Exchange (PKCE)

What is it?

The Proof Key for Code Exchange (PKCE) extension adds additional security to the OAuth 2.0 Authorization Code flow.

PKCE is typically pronounced the same as the word ‘pixie’.

What is its purpose?

PKCE’s main purpose is to prevent public clients from having an authorization code intercepted during an authentication exchange.

A public client is typically a native mobile application or a browser JavaScript application where the OAuth flow is handled completely client side. Since a Client Secret cannot be properly secured in these environments, the public client authenticates using only the Client ID and the PKCE parameters.

Note: Since public clients have no client_secret, this parameter should be ommitted from the request parameters for the OAuth flow (even if sent as an blank/empty value).

How do I use it?

The requesting app creates a secret (known as the Code Verifier) and submits a hash of that secret (known as the Code Challenge) on the initial authentication request.

The secret itself (the Code Verifier) is later submitted as part of exchanging the Authorization Code for an Access Token. This ensures that the client exchanging the Authorization Code for the Access Token is the same one that initially requested the Authorization Code.

It can be difficult to generate the correct values for the Code Verifier and Code Challenge from the command line.

It is recommended to use an OAuth client that supports PKCE.

Generating a code verifier

A client needs to generate a random string of characters. The string must be at least 43 bytes long and no more than 128 bytes. It must be composed of only the following characters:

  • English letters A-Z or a-z
  • Numbers 0-9
  • Symbols “-”, “.”, “_” or “~”.

Creating the code challenge

The code challenge is created by generating a SHA-256 byte hash of the code verifier. The result is then base64url-encoded.

Example code verifier and code challenge creation

NodeJS example
const crypto = require('crypto');
const codeVerifier = crypto
  .randomBytes(60)
  .toString('hex')
  .slice(0, 128);
const codeChallenge = crypto
  .createHash('sha256')
  .update(Buffer.from(codeVerifier))
  .digest('base64')
  .replace(/=/g, '')
  .replace(/\+/g, '-')
  .replace(/\//g, '_');

To check your work, use this code_verifier and ensure you get the listed code_challenge:

Valid output
code_verifier=e517c32aee2356891326604e79ad7d358154e124c157d762cbc8896fb13bfbc5d93a335cc27df714a9280e8249cbc3507143b3b7829d3fe9f62b9fce
code_challenge=4lKn4LVhzJzjx_BttEPuMcracgFKVKbTMmSKYAvA24Y

Check your work: Paste in a verifier or hit the create button to generate one.

code_verifier:
code_challenge:

How have others used it?

The Consumer API OpenID Connect Example on GitHub uses the Passport authentication middleware to handle PKCE support.

The Simple Plugin Example on GitHub uses the Node.js crypto library to handle PKCE support.

Additional details

OAuth 2.1

The OAuth 2.1 draft specification requires PKCE for all OAuth clients which use the Authorization Code flow.

Our v0 authentication endpoints include support for OAuth 2.1 in anticipation of the draft specification being approved in the near future.

Migration guide for Consumer API

Unversioned Authentication Endpoints

Do you have code that uses our deprecated and unversioned authentication endpoints when authenticating to the Consumer API?

If so, you’ll want to upgrade to use the v0 authentication endpoints.

We recommend reading the Guide on Migrating to the V0 OpenID Connect Endpoints.


Have a Question?
Have a how-to question? Seeing a weird error? Get help on StackOverflow.
Register for the Digital Toolkit Meetup where we answer technical Q&A from the audience.
Last updated Tue Nov 21 2023