Lion Cipher Lab
Stop token theft with DPoP: bind an OAuth token to a key so a stolen token is useless
- Identity & Access Management
- Intermediate
- ~45 min
- Free · no account required
Why it matters
A normal OAuth 2.0 access token is a BEARER token, and 'bearer' is the whole problem: like a paper banknote, it is valid for whoever is holding it, no questions asked. If that token ends up somewhere it should not — a log file, a crash report, a shared proxy, an SSRF response, a cross-site-scripting payload that reads it out of the browser — the attacker replays it and IS you 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: bind each token to a cryptographic key the legitimate client…
What you'll learn
- the difference between a bearer token and a sender-constrained (proof-of-possession) token
- how DPoP (RFC 9449) binds an access token to a client-held key pair
- generating an EC (elliptic-curve) key pair for a client
- building a DPoP proof JWT by hand: header typ 'dpop+jwt' + jwk, claims htm/htu/jti/iat (and ath for a resource request)
- reading the cnf.jkt confirmation claim and matching it to a JWK SHA-256 thumbprint (RFC 7638)
- requesting a DPoP-bound token from Keycloak and handling the DPoP-Nonce challenge
- proving that a stolen token fails without the matching private key (wrong key, missing proof, or downgraded to Bearer)
- knowing when to reach for DPoP vs mTLS-bound tokens (RFC 8705) vs just short token lifetimes
Steps in this lab
- The words first: bearer vs sender-constrained, and what DPoP actually is
- When to reach for DPoP — and when NOT to (read before you build)
- Start Keycloak in Docker (dev mode)
- Create a realm, a DPoP-enabled client, and a test user
- Set up the tiny signing script (Node + jose)
- Generate an EC key pair and compute its thumbprint (the future cnf.jkt)
- Build a DPoP proof and request a token from Keycloak
- Decode the token and prove cnf.jkt equals your key's thumbprint
- Use the token correctly at the resource endpoint (proof carries htm/htu/ath)
- Now steal the token: prove it is useless three ways
- The pro move: DPoP here, mTLS there, short tokens everywhere