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

State and nonce

All values in these examples are fictional.

The printer's request carries two values it generated for this attempt: state=demo-signin-3 and nonce=demo-nonce-3. Both are random in a real request, both are stored in the pending sign-in, and both come back. It is reasonable to wonder why one would not be enough.

Two values, two messages

They come back in different messages, and each protects the message it returns in.

state returns in the redirect to the callback, next to the code. As Correlating requests and responses explained, the printer uses it to find the pending attempt and to confirm that the response arrived in the same browser session that started it. A code delivered to a different session is not accepted.

nonce returns inside the ID token. The photo service copies the value from the request into the token's nonce claim and then signs the token. Nobody can change the nonce in a genuine ID token without breaking the signature, and the photo service puts demo-nonce-3 only in a token issued in answer to this request. When the printer finds demo-nonce-3 in a token it has validated, it knows the token belongs to this attempt.

That matters even though the token arrives directly from the token endpoint. Suppose an attacker has stolen the authorization code issued for one of your sign-ins. They start a sign-in of their own at the printer, so their browser has a pending attempt with its own state and nonce, and then deliver your code to the printer's callback in their browser, with their state. The state check passes, because the attempt is theirs. If nothing else stopped it, the printer would exchange your code, receive a perfectly genuine ID token for user-2048, and sign the attacker in to your printer account.

The nonce gives it away. The token carries the nonce from your request, but the attacker's pending attempt expects a different one. The printer rejects the token and signs no one in.

Creating a nonce

A nonce must be unpredictable and used for one attempt only. The printer generates it with the same cryptographically secure randomness it uses for state and the PKCE verifier. The readable demo-nonce-3 is a stand-in.

The printer keeps the expected nonce in the pending sign-in on its server, next to the verifier. A relying party that cannot keep server-side records for each attempt can instead put a random value in a protected cookie and send a hash of it as the nonce, then recompute the hash when the browser returns. Either way, the expected nonce is tied to the browser that started the attempt.

The printer compares the token's nonce claim with the stored value exactly, and only once. When the pending sign-in is claimed, its nonce goes with it, so a second token carrying the same nonce finds nothing to match. If the request sent a nonce and the ID token has none, that is a failure too, not a token that happened to skip an optional check.

A nonce does not stay secret the way the PKCE verifier does. It travels through the browser in the request and appears in the ID token. Its value comes from being unpredictable beforehand and bound to one attempt.

Alongside PKCE

Return to the stolen code. With PKCE, the exchange would never reach the nonce check. The printer would send the verifier stored in the attacker's pending attempt, which does not match the challenge in your request, and the token endpoint would refuse to issue anything.

So the two overlap here. Current OAuth security guidance accepts a properly checked nonce in place of PKCE for confidential OpenID Connect clients such as the printer, as protection against code injection. The printer uses both anyway. They are checked in different places, by different parties, so a mistake in one does not leave the sign-in unprotected.

ValueTravels inChecked byWhat it establishes
stateThe request and the redirectThe printer, at the callbackThe response belongs to an attempt started in this browser session.
iss in the responseThe redirectThe printer, at the callbackThe expected provider answered.
PKCE challenge and verifierThe challenge in the request, the verifier in the token requestThe photo service, at the token endpointWhoever redeems the code started the attempt.
nonceThe request, then the signed ID tokenThe printer, when validating the ID tokenThe ID token was issued for this attempt.

The nonce carries more weight in older flows that return an ID token directly through the browser, where nothing like the code exchange stands between a captured token and the relying party. OpenID Connect requires a nonce in those flows, and Understanding implicit and hybrid integrations covers them. Expiration and nonce checks shows where the nonce comparison sits among the other checks the printer makes.

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 ID token's signature, issuer, and audience are valid, but its nonce does not match the pending sign-in. What should the printer do?

QUESTION 2 OF 2Where does the printer find the nonce when the sign-in returns?

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