Encrypt Online
Choose theme

PKCE code verifier vs code challenge: exact bytes, exact encoding, common errors

A practical PKCE guide that shows the relationship between the verifier and challenge and the exact encoding steps that usually go wrong.

Encrypt Online Editorial Team3 min readEncoding & Transport
PKCE code verifier vs code challenge: exact bytes, exact encoding, common errors guide cover

Tip

Decode a small sample first and confirm whether you are changing representation, changing structure, or actually protecting content.

PKCE looks simple because the inputs are short strings. It still breaks regularly because it is not really a string problem. It is a bytes-and-encoding problem hidden behind URL-safe text.

The clean mental model is this: the code verifier is the original high-entropy secret, and the code challenge is a derived value sent earlier in the flow.

Summary

Definition: PKCE binds an authorization code flow to a client-generated secret by sending a challenge first and the verifier later.

Why it matters: The code challenge protects the flow even when the authorization code is intercepted, especially for public clients.

Pitfall: Most invalid-verifier errors are caused by hashing or Base64URL-encoding the wrong bytes, or by mutating the verifier after it was used to create the challenge.

The exact transformation path

Generate a high-entropy verifier string within the RFC 7636 length and character rules. For S256, hash the verifier bytes with SHA-256. Then Base64URL-encode the digest without changing the bytes or applying the wrong alphabet. That output is the code challenge.

What often goes wrong is an extra conversion step. Teams accidentally hash a UTF-16 representation, add standard Base64 instead of Base64URL, or edit the verifier before the token exchange. Each mistake produces a value that looks fine and fails anyway.

Why plain and S256 are not interchangeable defaults

The plain method uses the verifier itself as the challenge. S256 uses the derived challenge. Most modern deployments prefer S256 because it exposes less and aligns with what providers expect for stronger PKCE flows.

The operational point is to record which method you declared. A perfectly computed challenge can still fail if the server expects S256 and you told it plain, or vice versa.

Treat verifier handling like token handling

The verifier is not a casual debug string. It must survive the round trip exactly as generated. If it is stored in a session, copied between windows, or passed through a helper that normalizes text, the later exchange may fail even though the earlier authorization request succeeded.

That is why a dedicated PKCE tool is worth shipping. The value is not the math. The value is making the math difficult to do wrong.

Quick example

Use this when you want a compact reference for the S256 path.

What to notice: The verifier is the original secret. The challenge is derived from it. They are not meant to match as plain strings in S256 mode.

Text
verifier --SHA-256--> digest --Base64URL(no padding)--> challenge

Practical check

  • Generate the verifier once and store it exactly as generated.
  • For S256, hash the verifier bytes and then Base64URL-encode the digest.
  • Confirm the declared challenge method matches what you actually produced.

FAQ

Can I regenerate the verifier later if I know the challenge?

No. The verifier should be treated as the original secret and kept intact for the token exchange.

Why do providers reject values that look valid?

Because PKCE validation is byte-exact. A string that looks similar can still decode to the wrong bytes.

Developer workflow

Use this guide as a representation check before you move bytes between an API, token, URL, or file format.

  1. Encode or decode a small sample first, not the production payload.
  2. Confirm whether the step changes only representation or changes the underlying structure.
  3. Keep the original and transformed values together until the receiving system accepts the result.
Text
1. raw bytes or text
2. encode/decode for transport
3. decode back to confirm round trip
4. send only after structure still matches

References