Sender-constrain a token (DPoP)
Bind a token to a key you hold so a stolen copy is useless — RFC 9449 proof-of-possession.
Registering an OAuth client needs an invite code, which only an instructor can mint — ask for one at akhil@integrauth.com.
- 1
Generate an ES256 keypair, then complete ANY token grant with a DPoP proof header (JWS: typ dpop+jwt, htm POST, htu the token URL).
The Lab binds the minted access token to your key’s thumbprint (cnf.jkt) and returns token_type=DPoP — the token now only works when you can PROVE you hold the private key.
- 2
Call /oidc/userinfo (or /gateway/echo) with Authorization: DPoP <token> and a fresh proof carrying ath = SHA-256(token).
The resource server re-checks the proof and that its key matches the token’s cnf.jkt — a replayed proof (same jti) is rejected, and a stale one falls outside the ±300s window.
- 3
Present the SAME DPoP-bound token as a plain Bearer and watch it 401.
That’s the whole point: a leaked bearer copy of a sender-constrained token is worthless without the private key.
- 4
(Opt-in, off by default) When a deployment sets LAB_DPOP_NONCE_REQUIRED=1, retry a token request without a `nonce` claim and read the `use_dpop_nonce` challenge.
RFC 9449 §8: the server can demand a fresh, server-issued nonce in every proof, HMAC-signed over a short time window — a client can’t forge one or pre-generate proofs far in advance; the challenge response hands back the nonce to retry with.
Do it
This one happens on your account page — register a passkey, revoke a session, or enroll TOTP there.
Go to your account →Learn the theory
🩻 X-ray — what actually happened
Your own insert-only audit trail — the real server events, sanitized (never a secret), each linked to the lesson that explains it.