Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

Proof Key for Code Exchange (PKCE)

Suppose someone obtains the authorization code while it is returning to the printer. Should possessing that code be enough to exchange it for an access token?

It should not be. The Public and confidential clients lesson introduced PKCE, a secret the client creates for one authorization attempt so that only the client instance holding it can redeem the code. The printer prepares that secret before sending your browser away, and the authorization server checks it when the code comes back.

Preparing a verifier and challenge

The client generates a fresh secret called the code_verifier. A real verifier uses cryptographically secure randomness and is between 43 and 128 characters long, using letters, digits, and the allowed characters -, ., _, and ~.

For teaching only, we will use this predictable value so the calculation can be repeated:

code_verifier:
btl_training_verifier_for_one_attempt_only_2026

code_challenge:
qd-75t-gnweZAhIl6REjxxgFnPXGwvqYcxq3vlsaJYQ

code_challenge_method:
S256

Do not use that fixed verifier in a real client. Matching the required length does not make a predictable string a secure secret.

With S256, the client hashes the verifier using SHA-256 and encodes the resulting bytes using Base64url without padding:

challenge = BASE64URL_WITHOUT_PADDING(SHA256(ASCII(verifier)))

This is a hash transformation, not encryption. The server does not decrypt the challenge to recover the verifier.

Proving possession later

The client sends the challenge and method in the authorization request. It keeps the verifier with the pending transaction.

When the authorization server issues a code, it associates that code with the challenge. Later, the client sends the code and verifier to the token endpoint. The server applies the same transformation to the received verifier and compares the result with the challenge associated with the code.

An incorrect verifier makes the exchange fail. Copying the visible challenge does not give an attacker the verifier needed to produce that challenge.

Before authorization, the backend derives a challenge from verifier bytes using SHA-256 and unpadded Base64url, then sends the challenge through the browser. At the token endpoint, the received verifier is transformed and compared with the original challenge bound to the code. Client authentication and other token checks still apply.
The client sends the challenge first and keeps the verifier private. At the token endpoint, the server transforms the supplied verifier in the same way and compares it with the challenge bound to the code. View full-size illustration (opens in a new tab)

Understanding what the proof means

The verifier belongs to one attempt. It is not the printer's long-term client secret and does not establish the client's registered identity. Our confidential backend authenticates itself separately when making the token request.

Use PKCE with S256 in the flow taught here. Current security guidance requires PKCE for public clients and recommends it for confidential clients as well.

For a confidential client like the printer, the benefit is easy to miss. A stolen code is not much use to an attacker at the token endpoint, because redeeming it there requires the printer's client authentication. But the attacker does not need to redeem it. They can start their own connection on the printer's website and, when the photo service sends their browser back, swap your stolen code into the callback. The printer's backend would then redeem your code with its genuine credentials and attach your photo account to the attacker's printer session. This is authorization code injection. PKCE stops it: the printer redeems the code with the verifier saved for the attacker's attempt, which does not match the challenge bound to your code, so the exchange fails.

PKCE is not a complete defense against every form of credential theft. If an attacker compromises the client and obtains both the code and verifier, this particular check cannot distinguish their request from the client's. It also does not protect an access token after that token has been issued. Code interception and injection returns to stolen and injected codes, and Token theft and replay covers access tokens that escape after they are issued.

Try it in the Lab

PUT IT INTO PRACTICE

Check your understanding

Try these questions before moving on. If an answer isn't right, use the feedback and try again.

0 of 2 answered correctly

Enable JavaScript to answer these questions and save progress in this browser.

QUESTION 1 OF 2An attacker starts their own connection on the printer's website and swaps a code stolen from you into their callback. The printer's backend authenticates correctly at the token endpoint. What makes the exchange fail?

QUESTION 2 OF 2Does using PKCE remove this confidential client's need to authenticate at the token endpoint?

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

Learn identity