Summary
- DPoP replaces one property of a bearer token: possession of the token string is no longer enough. The presenter must also produce a fresh proof with the private key whose public-key thumbprint is bound to that token.
- The proof is deliberately narrow. It binds a method, a target URI without query or fragment, a creation time, a unique proof identifier, the token value and sometimes a server nonce. It does not sign the whole request or grant permission for the operation.
- A resource server still has to validate the token's issuer, status, audience, lifetime and privileges, coordinate replay state, reconstruct the right external URI and authorize the current subject, client, resource, action and object state.
The theft DPoP can stop
A support engineer opens a diagnostic bundle and finds an OAuth access token in a log. In a bearer system, that string is the credential. Anyone who can present it to an accepting resource server can exercise whatever authority the token represents until it expires or is revoked.
The logged token is DPoP-bound. The engineer copies it into another client and sends a request. The resource server expects two things: the token under the DPoP authorization scheme and a separately signed DPoP proof. The copied string is not enough. The engineer does not possess the private key corresponding to the public-key thumbprint recorded with the token. A new proof made with an attacker key will not match. A captured old proof will fail its method, URI, time, nonce or replay checks. The theft has been contained.
That is a real security gain. It is also the point at which dashboards often begin to overstate what happened.
The legitimate browser now makes the request. It has the bound key. Its proof signature verifies. The method and target URI match. The access-token hash matches. The proof is fresh and its identifier has not been seen. Every DPoP check is green.
The resource server still refuses the operation. The token was issued for another audience. Or it carries read authority while the request deletes a payment instruction. Or the account has been suspended since issuance. Or the object has already entered a state in which no client may alter it. Nothing is wrong with DPoP. Sender constraint answered one question, while authorization answered another.
From bearer possession to sender constraint
RFC 6750 defines the bearer property plainly: a party that holds the token can use it without demonstrating cryptographic key possession. Transport protection, careful storage, short lifetimes and audience restriction reduce the chance and value of leakage, but a copied bearer value remains portable inside its acceptance boundary.
RFC 9449 changes that boundary at the application layer. A client selects an asymmetric key pair. When it requests a token, it sends a signed proof. The authorization server can then bind the issued access or refresh token to the public key's JWK thumbprint. At a protected resource, the client presents both the token and a newly signed proof. The resource server confirms that the proof key is the key to which the token was bound.
The distinction from a bearer token is operationally important. Exfiltrating the token value without gaining the key or a usable signing interface no longer supplies a complete credential. RFC 9700 consequently recommends sender-constrained tokens, alongside audience restriction and least-privilege token design, as a defence against stolen-token misuse.
But binding a token to a key does not answer who controls the client now, why the token was issued, what the resource owner approved, or what the application may do. A key thumbprint is a deterministic identifier for key material. It is not a person, company, device posture, mandate or permission.
What the proof actually contains
A DPoP proof is a signed JWT. Its protected header explicitly identifies the object as dpop+jwt, names an asymmetric signature algorithm and carries the public JWK. Those fields allow the receiver to apply a DPoP-specific validation profile rather than feed an undifferentiated JWT into a generic “signature valid” path. RFC 8725 supplies the wider lesson: algorithms, issuers, audiences, types and validation rules are application choices, not claims a library should trust merely because they arrived inside a signed object.
The base proof payload contains four important claims. htm names the HTTP method. htu names the HTTP target URI, excluding query and fragment. iat records creation time. jti provides a proof identifier generated with enough unpredictability that accidental reuse should be negligible.
When an access token accompanies the request, the proof also carries ath, a SHA-256 hash of the exact token value. The receiver recomputes it. That prevents a proof captured beside one token from being paired with a different token, including another token issued for another user under the same proof key.
If the server has challenged the client with DPoP-Nonce, the next proof also carries that nonce. A current unpredictable nonce can make a pre-generated stockpile of signed proofs much less useful. It gives the server evidence that the signing capability responded to a value the server recently chose.
None of these claims is self-executing. The receiver must reject duplicate DPoP fields, parse one well-formed JWT, require the exact type, constrain the algorithm, verify the signature, exclude private material from the JWK, compare the method and URI, enforce the time window, recompute ath, match the token-bound thumbprint and apply the nonce rule it actually issued. A proof is not valid because it contains the right nouns.
Three bindings that should not be collapsed
DPoP uses related hashes at different stages, and confusing them produces gaps.
The first is token-to-key binding. The authorization server records the JWK thumbprint, commonly as cnf.jkt, with the token. At the resource server, that stored or introspected value must equal the thumbprint of the proof's public key.
The second is proof-to-token binding. The ath claim commits the proof to the exact access-token value presented on this request. It prevents token substitution but does not establish audience, scope or current validity.
The third, optional binding begins earlier. The dpop_jkt authorization-request parameter can bind an authorization code to the intended proof key. Without it, an attacker who obtains an authorization code and the other redemption material may attempt to redeem the code using a proof made with the attacker's own key, causing the resulting token to be bound to the wrong sender. Code-to-key binding closes that particular substitution path. It remains distinct from PKCE, client authentication and resource-owner authorization.
A system can implement one binding correctly and omit another. Evidence therefore needs stage names, not a single “PoP enabled” flag.
The request is only partly described
The htm and htu claims make a proof request-specific, but within a deliberately small definition. Method comparison prevents a proof for GET from being replayed as DELETE. URI comparison prevents a proof for one target from being carried to another.
The boundary matters. htu omits query and fragment. DPoP does not ordinarily cover request bodies or arbitrary header fields. If POST /transfer?account=A and POST /transfer?account=B have the same htu under the specification, the DPoP proof alone does not distinguish the query values. If a JSON body changes an amount or beneficiary, the base proof does not become a body signature.
That is not a defect hidden in the standard. DPoP is a sender-constraining mechanism, not a replacement for HTTP Message Signatures, an application idempotency key or a transaction authorization object. RFC 9110 supplies the HTTP semantics, while the application owns the meaning of query, body and current state. A profile can add claims, and the access token can carry bounded privileges, but the resource server must authorize the command it will actually execute.
Proxies complicate htu further. A client proves the external scheme, authority and path that it sees. A gateway may terminate TLS, rewrite a path or forward an internal host. If the resource server reconstructs the URI from the wrong side of that boundary, correct clients fail or unsafe alternatives are accepted. The external request context, trusted forwarding chain and normalization rules need an explicit owner.
Freshness is state, not syntax
iat and jti make replay control possible. They do not make it automatic.
The receiver chooses an acceptable age and clock-skew policy. It chooses the replay key, the retention period and the acceptance topology. If one resource-server region records a jti while another region has not yet seen that state, the same proof may pass twice. If check and write are not atomic, simultaneous copies can both observe “unused.” If a nonce is shared too broadly or retained too long, it becomes decoration rather than a current challenge.
Authorization-server and resource-server nonces are separate. A client that sends one server's nonce to another has not strengthened the proof; it has confused the challenge scope. Multi-issuer clients need to retain that boundary as carefully as the servers do.
There is another distinction. Rejecting a replayed proof is not the same as guaranteeing exactly-once business execution. A client can create two fresh proofs for two retries. Both may be cryptographically unique. The application must decide whether the underlying operation is idempotent, whether it has already committed, and whether a retry returns the previous result or performs another effect.
Key possession is neither identity nor consent
The public JWK in a proof tells the receiver which key verified the signature. It does not say who generated that key, whether it belongs to a registered client, whether a user controls the process, or whether the user approved this operation.
At the token endpoint, confidential-client authentication can coexist with DPoP; one does not substitute for the other. At the resource server, the access token supplies issuer-governed authorization context. The proof supplies sender constraint. The application supplies the final policy over resource and state.
This separation is particularly important in browsers. RFC 10017 explains how a non-extractable browser key can prevent malicious code from copying token and key material for later use elsewhere. Yet code already executing inside the application's origin can still invoke accessible browser capabilities, send requests in the live session or begin a fresh authorization flow. A key that cannot be exported can still be used by the wrong code in the right place.
If an attacker obtains both the token and the private key—or durable control of the signing interface—the sender constraint is undermined. Hardware-backed or non-extractable keys improve custody. They do not turn a compromised client into a trustworthy principal.
Running proof across the whole acceptance path
IANA records DPoP and DPoP-Nonce as permanent HTTP fields and maintains the related OAuth parameter registrations. That common vocabulary is valuable. It does not show that a deployment compares the same URI at every hop, shares replay state, rejects an algorithm consistently or preserves the resource decision.
Running-code evidence should follow a proof from issuance to consequence. Capture a privacy-safe hash of the proof, the public-key thumbprint, token type, ath result, normalized external and internal URI, proof age, nonce issuer, replay-store result, token issuer and audience, scope decision, resource-policy version and final commit identifier. Do not log raw access tokens or private keys.
Then test negative cases across independent components: copied token without the key; correct key with the wrong token; old proof; repeated jti; wrong method; external-to-internal URI rewrite; missing or foreign nonce; token for another audience; insufficient scope; suspended subject; already-completed operation. A system that can explain every refusal has more authority evidence than one that displays a single green DPoP badge.
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