Lion Cipher Lab
Build a CAEP / Shared Signals receiver from scratch — verify SETs and kill a live session on a revocation signal
- Identity & Access Management
- Advanced
- ~75 min
- Free · no account required
Why it matters
Every OAuth 2.0 / OpenID Connect system hands out access tokens that live for minutes to hours. That TTL is a bet: 'nothing about this user's trust will change before the token expires.' The bet loses constantly — someone is fired, a laptop is stolen, a password is reset after phishing, an admin revokes a session — and a pure bearer-token relying party keeps honoring the still-valid, still-unexpired token right up until it dies on its own. You can shrink the window with very short TTLs (now you're re-minting tokens constantly) or by calling the issuer's introspection endpoint on every request…
What you'll learn
- the gap static token validation leaves: an unexpired bearer token stays valid after the user is fired / the device is stolen, until it expires — polling and push both close it, differently
- the four moving pieces of the Shared Signals Framework: a Transmitter, a Receiver, a Stream (the receiver's config + audience), and the SET it carries
- reading a Security Event Token (SET, RFC 8417): a JWT with header typ 'secevent+jwt' and an `events` claim keyed by a CAEP event-type URI (session-revoked, credential-change, token-claims-change, assurance-level-change)
- building a receiver endpoint that VERIFIES a pushed SET before acting on it: RS256 signature against the transmitter's JWKS selected by kid, iss, aud=your stream, iat, and a well-formed events object
- the two checks unique to a signal receiver on top of ordinary JWT validation: `aud` (is this SET meant for MY stream, not another receiver's?) and `jti` replay (did I already act on this exact signal?)
- mapping a CAEP subject identifier (formats: iss_sub / email / opaque) to a local session, then REVOKING it — deleting server-side session state so the very next request 401s
- returning the RFC 8935 push responses a transmitter expects: 202 (accepted) on success, 400 with an err/description body on rejection
- the judgment: acking before you act loses signals; a signal you can't verify is worse than none; push complements — never replaces — short token TTLs and introspection
Steps in this lab
- The gap: a valid token outlives the trust behind it
- The four pieces, and the shape of a SET
- Stand up the local transmitter's keys and publish a JWKS
- Build the receiver: a session, a protected route, and a SET endpoint that VERIFIES before it acts
- Build the transmitter: mint and PUSH a real signed SET
- PROVE it: fire a session-revoked SET and watch a live session die
- Break it: forged signature, wrong audience, and replay are all REJECTED
- The judgment: a signal you can't verify is worse than no signal