DPoP-Nonce auth both
A server-issued challenge value that must be embedded in subsequent DPoP proofs, adding freshness guarantees beyond timestamp checking alone.
What it does
DPoP-Nonce is a server-issued, single-use challenge value that authorization servers and resource servers can require clients to embed in their next DPoP proof. It exists to close a gap plain timestamp-based freshness checking (the iat claim in a DPoP JWT) leaves open: without a server-provided nonce, an attacker with a narrow window of opportunity could still theoretically pre-generate and use a DPoP proof within its valid timestamp range. Requiring a server-issued nonce that changes per-challenge makes proofs meaningfully harder to precompute or reuse.
Syntax
Server issues a nonce (as a response header):
DPoP-Nonce: eyJhbGciOiJIUzI1NiJ9.opaque-nonce-value
Client includes it in the next DPoP proof's payload:
{
"jti": "unique-request-id",
"htm": "POST",
"htu": "https://api.example.com/resource",
"iat": 1723999999,
"nonce": "eyJhbGciOiJIUzI1NiJ9.opaque-nonce-value"
}
The nonce challenge-response flow
- Client sends a request with a DPoP proof, but without a nonce (or with an expired/incorrect one).
- Server rejects the request, responding
400 Bad Requestand issuing a fresh nonce via theDPoP-Nonceresponse header. - Client generates a new DPoP proof, this time including the server-provided nonce in its payload, and retries the request.
- Server validates the proof (including the nonce matches what it issued) and processes the request normally.
- The server may periodically rotate the required nonce, triggering the same challenge-response cycle again.
This means a client implementing DPoP correctly needs to handle an extra round trip on the first request (or whenever the nonce rotates) — something worth designing for rather than treating as an unexpected error case.
Common mistakes and gotchas
Not implementing the retry-with-nonce flow. A client that doesn't recognize the 400 + DPoP-Nonce response pattern and automatically retry with the nonce embedded will simply fail to authenticate against servers that require nonces — this is a specific flow that needs deliberate client-side handling, not something that happens automatically just by sending a DPoP proof.
Treating nonce support as optional when the server requires it. Whether a nonce is required is up to the specific authorization/resource server's policy — some require it, some don't. Client implementations need to handle both cases (server that never issues a nonce, and server that does and expects it in every subsequent proof) rather than assuming one universal behavior.
Caching or reusing a nonce beyond its validity. Nonces are meant to be used for a limited time/number of requests before the server rotates them — continuing to use a stale nonce will eventually trigger a fresh 400 + new nonce challenge, so clients should be prepared to handle repeated rotation throughout a session, not just once at the start.
Confusing this with a CSRF token or session nonce. DPoP-Nonce serves a narrow, specific purpose within the DPoP proof-of-possession mechanism — it's not a general-purpose anti-CSRF mechanism and shouldn't be conflated with unrelated nonce-based security patterns used elsewhere in an application.
Real-world examples
Initial request rejected, server issues a nonce:
POST /token HTTP/1.1
DPoP: eyJ0eXAiOiJkcG9wK2p3dCJ9...(no nonce claim)
HTTP/1.1 400 Bad Request
DPoP-Nonce: xyz-fresh-nonce-value
{"error": "use_dpop_nonce"}
Client retries with the nonce embedded, succeeds:
POST /token HTTP/1.1
DPoP: eyJ0eXAiOiJkcG9wK2p3dCJ9...(includes "nonce": "xyz-fresh-nonce-value")
HTTP/1.1 200 OK
FAQ
Do all DPoP implementations require a nonce?
No — nonce support is at the discretion of the specific authorization/resource server. A client implementing DPoP needs to gracefully handle both servers that require nonces and ones that don't.
What happens if my client doesn't handle the nonce challenge-response correctly?
Requests to servers requiring a nonce will keep failing with 400 Bad Request and an use_dpop_nonce error, since the client never retries with the required nonce embedded in its proof — this looks like a persistent authentication failure rather than an obvious "you forgot a header" error.
How often does the required nonce change?
This is entirely up to server policy and isn't fixed by the spec — some servers rotate nonces per-request, others less frequently. Client implementations should be resilient to unexpected rotation at any point, not assume a fixed refresh interval.
Is DPoP-Nonce sent on every single request?
The server only issues it via the DPoP-Nonce response header when it wants to challenge or rotate the nonce — clients then include the current known nonce value in their DPoP proof payload on subsequent requests, not necessarily on every single response/request pair.
Fun fact
The nonce mechanism in DPoP mirrors a much older security pattern from HTTP Digest Authentication (RFC 7616), which also used server-issued nonces to prevent replay attacks decades before DPoP existed. It's a good example of a proven cryptographic freshness pattern getting reapplied to solve a structurally similar problem in a completely different, more modern authentication context — proof that some security design patterns remain fundamentally sound even as the surrounding protocols evolve dramatically.