Bearer
Photocopy
Whoever holds the string may use it until it expires. Prompt injection, logs, and traces are copy machines.
- Thief
→ same pass, no key needed →
API
IETF · September 2023
RFC 9449
D. Fett, B. Campbell, J. Bradley, T. Lodderstedt, M. Jones, D. Waite
OAuth 2.0 Demonstrating Proof of Possession (DPoP) (RFC 9449) is RFC, September 2023. If the agent must use OAuth bearer tokens, DPoP is the most deployable way to make a stolen token from a prompt injection less useful. It is not a substitute for not putting tokens in the model context.
At a glance
Actors
Animated sequence · DPoP vs Bearer
Photocopy, or pass glued to a key
A Bearer token is a photocopy: whoever holds the string may use it. DPoP (RFC 9449) glues the pass to a key. The client generates a key pair, then sends a DPoP proof JWT on the token request AND on every resource request (htm/htu). The access token's cnf.jkt must match. Stolen paper without the private key is a blank.
Now · 1/12· Discover· RFC 6750You are here
Authorization server→Client with key·Mints a Bearer access token — just a string
The AS issues token_type=Bearer. Anyone who copies the string can present Authorization: Bearer.
Why Contrast hop. Bearer means possession of the string is authorization. The authorization-code grant that produced this token is the OAuth 2.1 sequence — not replayed here.
A pass that is a photocopy — whoever holds the paper gets in.
Solid = from the spec
RFC 9449. DPoP is application-layer proof and works through TLS proxies. AAuth uses HTTP Message Signatures instead — do not stack proofs naively. Proofs are required on the token request and on each resource request.
In one board · Bearer vs DPoP
Bearer
Photocopy
Whoever holds the string may use it until it expires. Prompt injection, logs, and traces are copy machines.
→ same pass, no key needed →
DPoP
Glued to a key
Each request carries a short-lived proof JWT covering method and URL. Stolen paper without the private key is a blank.
→ pass + fresh proof →
RFC 9449. DPoP is application-layer proof — it works through TLS proxies. AAuth uses HTTP Message Signatures instead; do not stack proofs naively. mTLS is the other glue.
Sequence above; this list is the same hops for reading and search. Each row is one message.
Authorization server→Client with keyRFC 6750Mints a Bearer access token — just a string
Client with key→APIRFC 6750Authorization: Bearer — the API trusts the string
Client with key→ThiefRFC 6750Logs, traces, or prompt injection photocopy the string
Thief→APIRFC 6750Same pass, no key needed — the API cannot tell
Client with key→Client with keyRFC 9449Generates a DPoP key pair and keeps the private key
Client with key→Authorization serverRFC 9449Token request with a DPoP proof JWT (htm=POST, htu=token endpoint)
Authorization server→Authorization serverRFC 9449AS checks the DPoP proof: signature, htm, htu, iat
Authorization server→Client with keyRFC 9449Issues an access token with cnf.jkt (thumbprint of the client's DPoP key)
Client with key→APIRFC 9449Resource request: Authorization: DPoP plus a new DPoP proof JWT (htm/htu of this call)
API→APIRFC 9449RS checks cnf.jkt against the proof's JWK and verifies htm/htu
API→Client with keyRFC 9449Responds — the caller proved the key the token is glued to
Thief→APIRFC 9449Photocopy without the private key — 401, the paper is a blank
01
Bearer access tokens are reusable if stolen from an agent prompt or log. DPoP (RFC 9449, September 2023) binds an access token to a client key using a signed proof JWT on each request, without requiring mTLS — the most deployable sender-constraint for agents that are not in a mesh.
It is not a substitute for keeping tokens out of model context. A stolen token plus a stolen key is still game over. It does stop 'I found a token in a gist' replay from a different machine.
02
The client's DPoP key is the sender. The AS puts the JWK thumbprint in the access token cnf.jkt. The RS requires a fresh proof signed by that key covering htm and htu. TLS-terminating proxies do not break DPoP the way they break mTLS passthrough.
03
Client generates a DPoP key pair. Token endpoint (and later RS) receive a DPoP header: a JWT with typ dpop+jwt, jwk in the header, claims htm, htu, iat, jti, and when presenting an access token, ath (hash of the token). AS issues token_type=DPoP with cnf.jkt. RS checks proof freshness, uniqueness of jti (replay cache), and binding.
Nonce mechanism lets the RS/AS demand a fresh proof. Authorization codes can be bound to the DPoP key (FAPI 2.0 requires this when using DPoP).
04
Flow 1
Client creates a DPoP key (often ephemeral per session).
Token request includes a DPoP proof. AS returns an access token with cnf.jkt.
Each RS call: new proof covering this method and URI, plus the access token, Authorization scheme DPoP.
RS verifies token signature/introspection, jkt matches the proof key, proof signature, htm/htu, iat window, jti not replayed.
05
Sender-constrained authentication of the API call. The token still carries authorization. DPoP does not identify the user; OIDC still does that at the AS.
06
Alternative sender-constraint. FAPI 2.0 allows either. mTLS is stronger at the transport; DPoP survives TLS termination.
9700's recommended app-layer PoP.
AAuth's PoP. Do not mix proofs naively on one request.
WPT is the WIMSE analogue (Authorization: WPT + WIT header).
MCP still specifies Bearer; adding DPoP is an AS/RS profile, not required by MCP 2026-07-28.
07
Without a jti cache and tight iat, a captured proof+token pair replays at the same URI. Use nonce where possible.
Proxies that rewrite URLs break htu. Normalize carefully; do not skip the check.
If the DPoP private key sits next to the token in the same dump, you have not gained much. Isolate keys.
08
RFC 9449, September 2023. Stable. Ship it for any agent that must use OAuth tokens outside a mesh. https://www.rfc-editor.org/rfc/rfc9449.html
DPoP is application-layer PoP and works through TLS-terminating proxies. AAuth instead uses HTTP Message Signatures (RFC 9421) as its PoP. Do not mix proofs naively.