Lion Cipher Lab
Rotate refresh tokens and revoke sessions with Keycloak
- Identity & Access Management
- Intermediate
- ~55 min
- Free · no account required
Why it matters
Getting a token is the easy half of OAuth. The hard, high-stakes half is the token LIFECYCLE — what happens after issuance, when a token ages, gets refreshed, gets stolen, or has to be killed on demand. Every real breach postmortem that involves stolen credentials comes down to two questions: could the attacker keep refreshing access indefinitely, and could the defender cut the session off fast? This lab makes both answers concrete against a real authorization server. You will obtain a refresh token — the long-lived credential an app uses to get fresh access tokens without re-prompting the…
What you'll learn
- obtaining an access_token and refresh_token from a Keycloak realm and decoding the refresh token's JWT payload (exp, typ)
- refreshing an access token by POSTing grant_type=refresh_token to the /token endpoint (RFC 6749 §6)
- turning on refresh-token rotation (Keycloak 'Revoke Refresh Token') and proving a reused old refresh token fails with invalid_grant
- explaining why rotation + reuse-detection catches a stolen refresh token
- revoking a token at the RFC 7009 revocation endpoint (/protocol/openid-connect/revoke) and proving the token stops working
- ending a user session from the Keycloak admin console (logout / delete session) and seeing the refresh token die with it
- using the token introspection endpoint to watch "active" flip from true to false across revocation
- reasoning about session lifetimes: SSO Session Idle vs SSO Session Max, Access Token Lifespan, and offline tokens vs regular refresh tokens
- knowing why public clients (SPA/mobile) MUST rotate and should not expose refresh tokens to browser JS (the BFF pattern), and how DPoP/mTLS make a stolen token useless
Steps in this lab
- What a refresh token is, and why its lifecycle is the whole game
- Start a real authorization server: Keycloak in Docker
- Create a realm, a client, and a test user
- Get an access token AND a refresh token
- Decode the refresh token and read exp / typ
- USE the refresh token: grant_type=refresh_token
- Turn ON rotation and PROVE the old token is dead
- Watch introspection: active true, before revocation
- REVOKE: kill the token (RFC 7009) and the session (admin)
- The timers that govern every session
- Why this, when NOT to, and the pro way