Lion Cipher Lab
Certificate-bound access tokens (RFC 8705): make a stolen token useless without the client's TLS certificate
- Identity & Access Management
- Advanced
- ~60 min
- Free · no account required
Why it matters
A normal OAuth 2.0 access token is a BEARER token, and 'bearer' is the whole risk: like a paper banknote, it is valid for whoever holds it, no questions asked. Copy that token out of a log line, a proxy dump, a crash report, or an SSRF response and the attacker replays it and IS the client until it expires. Short lifetimes shrink that window but never close it. The professional fix is to stop making tokens spendable by anyone who holds them — to SENDER-CONSTRAIN them, binding each token to a secret the legitimate client owns so that merely possessing the token is not enough. RFC 8705 does…
What you'll learn
- the difference between a bearer token and a sender-constrained (proof-of-possession) token
- RFC 8705's two distinct mechanisms: mTLS client authentication (§2) vs certificate-bound access tokens (§3) — and which one binds the TOKEN
- computing an X.509 certificate thumbprint the RFC 8705 way: x5t#S256 = base64url(SHA-256(DER-encoded leaf certificate))
- minting a local Certificate Authority and issuing client + server certificates with openssl
- building a Node.js HTTPS server that requests a client certificate (requestCert / rejectUnauthorized)
- reading the presented client certificate off the live TLS socket (getPeerCertificate().raw) and hashing its DER form
- issuing a signed JWT access token carrying the cnf claim with member x5t#S256
- verifying at the resource server that the token's cnf thumbprint equals the thumbprint of the certificate ACTUALLY presented on the connection
- proving a stolen token is rejected (401) when replayed from a different certificate
- knowing when to reach for mTLS-bound tokens vs DPoP vs plain mTLS client auth
Steps in this lab
- The words first: bearer vs sender-constrained, and RFC 8705's two mechanisms
- Make the project and install the one dependency (jose)
- Mint a local CA and certificates, and compute a thumbprint by hand
- Build the token issuer (HTTPS server that binds the token to the presented cert)
- Build the resource server (verify the token AND the presented certificate)
- Prove it: legit client gets 200, a stolen token replayed from another cert gets 401
- The judgment: mTLS-bound here, DPoP there, and the failure modes that bite