Summary
- Revision 11 of
draft-ietf-oauth-attestation-based-client-authwas posted on 3 September 2026 and entered OAuth Working Group Last Call on 8 September; comments are due by 22 September. - Server challenges are optional. When used, their lifetime and whether they are single-use or reusable are solely server local policy. A client must use the latest challenge and may reuse it.
- A single-use server rejects the second attempt with
use_attestation_challenge, sends a fresh value, and expects one retry rather than an indefinite loop. DPoP combined mode uses RFC 9449’s nonce path instead. - Revision 11 advertises proof methods and signing algorithms, but not consumption or replay semantics. Daniel Kade proposes a profile-level freshness-policy declaration; it is editorial analysis, not an IETF requirement.
Last Call begins with an undisclosed choice
The OAuth Working Group Last Call notice opened on 8 September and asks participants to state support or explain objections by 22 September. The Datatracker record identifies revision 11 as the current working-group draft. This is a real governance threshold: the group is asking whether the document is ready to progress. It is not an approval notice, an RFC, or evidence of IETF-wide consensus.
The draft addresses a deployment problem that ordinary shared-secret client credentials handle poorly. A Client Attester issues a signed Client Attestation JWT about a particular software instance. That instance then proves possession of the corresponding private key when it talks to an authorization server or protected resource. The two objects answer different questions: the attestation says what an attester vouches for; the proof says the requester controls the instance key now.
Freshness sits between those claims and the receiving server. In the dedicated attestation_pop_jwt mode, the proof contains an issued-at time, a unique jti and, when supplied, the server’s opaque challenge. A server can deliver that challenge in an error, in another prior response or through a published challenge endpoint. The client must put the most recently received value into its next proof.
The important sentence in revision 11 does not prescribe a universal lifetime or one-time rule. Both are “determined solely” by the local policy of the authorization server or resource server. The client is explicitly allowed to put the same challenge into more than one Client Attestation PoP JWT. If the server accepts a value only once, the second use fails.
That is internally consistent. It also means two fully conforming servers can demand opposite client behaviour. One may issue a value that survives a short burst of requests. Another may consume it at the first accepted proof. A client cannot infer which contract it has received from the challenge bytes; the value is opaque by design.
Failure is the negotiation mechanism
Revision 11 closes the protocol loop after rejection. An authorization server returns HTTP 400 and a use_attestation_challenge error; a resource server uses HTTP 401 and the same error in its authentication response. Both must attach a fresh OAuth-Client-Attestation-Challenge header. The client should build a new proof and retry once. It must not retry forever.
That rule prevents a badly aligned pair from spinning without bound. It does not prevent the first avoidable failure. Suppose a fleet obtains a challenge proactively from the endpoint and sends ten concurrent token requests. A reusable-policy server may accept all ten proofs, subject to its other replay checks. A single-use server can accept one and reject the rest. The clients then refresh and retry, but “retry once” does not tell the fleet how to serialize issuance, share values across processes or distinguish policy rejection from a racing peer that consumed the challenge first.
The distinction matters because a challenge and a proof identifier protect different things. Every Client Attestation PoP JWT carries a mandatory jti; the server can retain witnessed identifiers for the validity window and reject a byte-for-byte replay. A server-generated challenge can add server-controlled freshness. If the server retains witnessed challenge values, it gains stronger replay detection with a value of its choosing, at the cost of state and possibly another round trip.
The security section deliberately permits another design: a self-contained challenge with no seen-value store. That scales better but provides freshness only; the same proof can still be replayed inside the accepted window unless another mechanism catches it. A third arrangement binds one expected challenge to a Client Instance session. These are not cosmetic implementation variants. They create different state costs, concurrency behaviour and replay guarantees.
The draft is careful about the fallback. Challenge support is optional in order to simplify mandatory implementation, while jti remains required. It also says servers should check an acceptable time window. A deployment that has “turned on challenges” therefore has not answered whether it consumes them, witnesses them, binds them to a session or merely encodes a timestamp in a self-contained value.
DPoP is a separate freshness lane
The document defines two proof modes. Normal mode sends a dedicated Client Attestation PoP JWT. Combined mode reuses one DPoP proof both to demonstrate the instance key and to support sender-constrained access tokens. Revision 11 makes the separation sharper: combined mode exclusively uses the DPoP nonce mechanism.
That means a missing or unacceptable nonce in combined mode produces use_dpop_nonce and a fresh DPoP-Nonce header, not the generic attestation-challenge error. The new challenge endpoint may deliver a DPoP nonce proactively, but it does not merge the two semantics. A library that treats attestation_challenge and DPoP-Nonce as interchangeable freshness tokens would erase a distinction the revision has just made normative.
The official comparison with revision 10 records that clarification alongside the optional-challenge error rule and the ability to return a DPoP nonce from the endpoint. Those changes make the wire behaviour easier to implement. They also make the remaining discovery boundary easier to see: a client can learn where to fetch a value, but not the server policy that will consume it.
Metadata stops before the expensive decision
Revision 11 adds client metadata for supported proof methods and signing algorithms, using the general model described by RFC 7591. Server metadata can similarly advertise attestation_pop_jwt, dpop_combined and accepted algorithms. If a challenge endpoint exists, its URL can be published. A client can therefore rule out several incompatible combinations before generating an expensive proof.
The published vocabulary stops just before the policy most likely to alter request scheduling. It does not state whether a challenge is required, how long it remains acceptable, whether it is reusable or consumed, whether the server witnesses values, whether a self-contained value gives freshness without replay protection, or whether a particular rule belongs to normal or combined mode. Nor does it give operators a policy version to correlate with a sudden rise in second-use errors.
Keeping exact lifetimes out of public metadata can be sensible. A server may not want to advertise a narrow replay window, and load or risk can justify dynamic values. But secrecy does not require total opacity. A declaration can say single-use without exposing storage internals, or publish a coarse lifetime class rather than a number of seconds.
The most proportionate remedy is a profile-level freshness-policy object, not a rewrite of the base protocol. For each proof mode, it would say whether server-provided freshness is supported or required; which issuance paths are active; whether consumption is reusable, single-use or session-bound; whether the replay posture is witnessed-state or self-contained freshness-only; the permitted automatic retry count; and a policy epoch. A signed discovery receipt could bind that declaration to the metadata instance a client acted upon.
This proposal is not part of revision 11. It is not current OAuth working-group consensus. The draft does, however, invite ecosystems and other specifications to profile its use. That is the right governance layer for a deployment contract: narrow enough to preserve local choice, visible enough to stop each vendor from inventing an undocumented one.
Sources
- IETF Datatracker — OAuth 2.0 Attestation-Based Client Authentication
- Revision 11
- Revision 10
- Official revision 10–11 comparison
- OAuth Working Group Last Call notice
- OAuth Working Group
- RFC 9449 — Demonstrating Proof of Possession
- RFC 7591 — OAuth Dynamic Client Registration
- RFC 6749 — OAuth 2.0
- RFC 7519 — JSON Web Token
Member Briefing
Deeper Profile Context
Sign in with the right membership level to unlock the full briefing and source notes.
Only for Strategic Circle
Strategic Circle
Open to all readers. Unlock profile briefings after joining and signing in.
Join Strategic CircleOnly for Leadership Alliance
Leadership Alliance
For qualified IP-asset owners and management; sign in to unlock alliance briefings.
Join Leadership Alliance

