A bearer token works for whoever holds it, wherever it came from. A sender-constrained token, using DPoP or mutual TLS, is bound to a key, so a stolen copy is not enough. RFC 9700 says authorization and resource servers should sender-constrain access tokens.
The bearer problem
RFC 6750 defines bearer tokens. Possession is the only proof. If a token leaks through logs, a proxy, malware or a bug, whoever has it can call the API until it expires.
RFC 6750 itself recommends several mitigations: protect token integrity, name the intended resource server in the token, use TLS, and keep lifetimes short. It notes that tokens valid for an hour or less reduce the impact of leakage.
Those help. They do not remove the core issue.
Option 1: DPoP
RFC 9449 defines Demonstrating Proof of Possession. The client holds a key pair. It signs a small JWT proof and sends it in a DPoP header. The authorization server binds the issued token to the public key, and the resource server checks that each request is signed by the matching private key.
It was designed for cases where transport level options are impractical, such as browser based single page apps and installed applications. It also limits replay of a token against a different endpoint.
Option 2: mutual TLS
RFC 9700 names mutual TLS (RFC 8705) alongside DPoP. The token is bound to the client certificate, so the resource server checks the certificate presented on the connection.
It suits server to server calls where you control certificate issuance. It is harder in browsers.
What DPoP does not do
RFC 9449 is clear about limits:
- It does not replace HTTPS.
- It is not a client authentication method.
- It does not stop attackers who run code inside the client, such as through XSS, because that code can still create valid proofs.
- It does not sign the request body or most headers, so message integrity relies on TLS.
- A valid proof alone is not an access control decision.
- Proofs can be replayed within their validity window unless servers track their unique identifiers, and can be pre-generated unless servers use nonces.
Choosing
- Internal service to service, you issue certificates: Reasonable choice: Mutual TLS
- Browser app or mobile app calling your API: Reasonable choice: DPoP
- Low risk, short lived tokens, no refresh: Reasonable choice: Bearer with short lifetime and audience checks
- High value actions: Reasonable choice: Sender-constrained plus re-authentication
Whatever you pick, keep the other basics: restrict token audience, verify it on every request, and for public clients use refresh token rotation or sender-constrained refresh tokens, as RFC 9700 says.
Where tokens leak
- Query strings, which end up in logs. See where to send a bearer token.
- Verbose error messages and debug logs.
- Browser storage readable by injected scripts.
- Copy-pasted curl commands in tickets.
Quick check
Does DPoP make XSS harmless?
No. RFC 9449 says it does not stop attackers who run code inside the client, since that code can still create valid proofs.
Do I need this for every API?
Not necessarily. It is most valuable where a stolen token would be costly. RFC 9700 says "should", not "must".
Safeguard's agent identity and policy features address how automated agents authenticate, and the free scan at gold.safeguard.sh/scan covers dependencies in your auth stack.
Sources
- RFC 6750 The OAuth 2.0 Bearer Token Usage
- RFC 9449 OAuth 2.0 Demonstrating Proof of Possession (DPoP)
- RFC 9700 Best Current Practice for OAuth 2.0 Security
Last reviewed: 19 October 2026.