Sender-Constrained Tokens (DPoP / mTLS) and Refresh Token Rotation
Overview
A normal Bearer token can be used by "anyone who holds it," so if stolen, an attacker can use it directly. The mechanism that prevents this is the sender-constrained token, which binds the token to a specific client's key. There are two ways to achieve it: DPoP and mTLS.
For long-lived refresh tokens, rotation is used in combination. OAuth 2.1 / the Security BCP requires refresh tokens for public clients that hold tokens in the browser/device to be either rotated or sender-constrained.
If tokens are kept server-side (as in the BFF pattern), there is no token on the client to steal, so neither DPoP nor mTLS is needed. Sender-constraining matters for public clients that must hold tokens on the device (native mobile apps, etc.).
The weakness of Bearer tokens
Bearer tokens assume "possession = right to use" and carry no binding of "whose token this is." Sender-constrained tokens add a "proof of key possession" here.
mTLS (Mutual TLS) — RFC 8705
The client presents a TLS client certificate and binds the token to it. The token embeds the
certificate thumbprint (x5t#S256 in the cnf claim), and the resource server verifies that it matches
the certificate presented on the TLS connection.
- Pros: completes at the TLS layer; robust.
- Cons: requires PKI (certificate issuance, distribution, revocation), which is operationally heavy. Unsuitable for public clients.
DPoP (Demonstrating Proof-of-Possession) — RFC 9449
The client generates its own key pair and attaches a signed DPoP proof (JWT) in the DPoP
header on every request. The token is bound to the public-key thumbprint (cnf.jkt), and the resource
server verifies that the proof was signed with the key bound to that token.
POST /resource
Authorization: DPoP <access_token>
DPoP: <proof-jwt> # contains htm(method), htu(URL), iat, jti; signed with the client's private key
access_token cnf: { "jkt": "<SHA-256 thumbprint of the public key>" }
- Pros: no PKI, lightweight. Suitable for SPAs, mobile, public clients.
- Cons: requires proof generation/validation on both client and server.
DPoP vs. mTLS comparison
| Aspect | DPoP (RFC 9449) | mTLS (RFC 8705) |
|---|---|---|
| Binding target | App-generated key pair | TLS client certificate |
| PKI | Not required | Required |
| Implementation weight | Lightweight (app layer) | Heavy (infra/cert management) |
| Suited clients | Public (mobile/SPA) | System-to-system / high assurance |
| General recommendation | Lightweight, good for public | Robust but high operational cost |
Refresh token rotation
Each time a refresh token is used, a new refresh token is issued and the old one is invalidated.
- If an old (already-used) refresh token is re-presented, it is treated as a sign of leakage/copy, and the entire token family is invalidated (reuse detection).
- It is not sender-constraining, but it minimizes the window of damage from a leak.
Requirements for public clients (OAuth 2.1)
OAuth 2.1 / the Security BCP requires one of the following for a public client's refresh token.
- Rotation (with reuse detection)
- Sender-constraining (DPoP or mTLS)
When to use what
- Web (browser) apps: keep tokens server-side via BFF → no binding needed (the simplest).
- Native mobile / SPA (public): tokens are on the device, so use rotation as a baseline and consider DPoP-based sender-constraining to harden further.
- High-assurance system-to-system: consider mTLS.
Summary
- Bearer tokens are "possession = right to use," so a stolen token is replayable.
- Sender-constrained tokens bind the token to a key and prevent replay on theft. DPoP (no PKI, lightweight) and mTLS (high assurance, heavy) are the two methods.
- Refresh token rotation minimizes leak damage via reuse detection.
- Keep tokens server-side and no binding is needed. Rotation/DPoP matter for public clients that hold tokens on the device.
Related documents
- BFF Pattern and the Token-Protection Security Model
- Server-side Token Store and Distributed Sessions
- OpenID Connect and OAuth 2.0
- Bearer Authentication
- TLS/SSL Basics