Skip to content
Free lab

Token Lifecycle Lab

A token breach is rarely a cracked signature — it is a lifecycle that was set up wrong. Work a queue of OAuth 2.0 / OIDC token setups and call each one: sound, or name the defect — an access token that lives for hours, a refresh token that never expires, a static (un-rotated) refresh token, rotation with no reuse detection, a refresh token in localStorage, no revocation on logout or breach, or an over-broad scope that no audience restricts. You are scored on catch rate against false positives — because flagging a sound setup (a secure-enclave mobile store, a refresh-less service, a long-but-bounded remember-me) is its own failure. Clear the queue clean.

The real job. More noise, a tighter clock.

0sPro

Token-handling queue

Call each OAuth / OIDC token setup: sound, or name the single lifecycle defect.

#1

first-party SPA

Public SPA (browser, PKCE)
access TTL10 min
refresh TTL14d absolute · 12h idle
rotationyes
reuse detectyes
storagehttpOnly + Secure + SameSite cookie
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Customer dashboard — browser single-page app

Verdict

#2

SPA, long access token

Public SPA (browser, PKCE)
access TTL24 h
refresh TTL14d absolute · 12h idle
rotationyes
reuse detectyes
storagehttpOnly + Secure + SameSite cookie
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Internal admin console — browser SPA

Verdict

#3

mobile, eternal refresh

Native mobile app (PKCE)
access TTL10 min
refresh TTLno absolute expiry · 24h idle
rotationyes
reuse detectyes
storageplatform secure storage (Keychain / Keystore)
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Consumer mobile app

Verdict

#4

SPA, static refresh

Public SPA (browser, PKCE)
access TTL10 min
refresh TTL30d absolute · 24h idle
rotationno
reuse detectno
storagehttpOnly + Secure + SameSite cookie
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Marketing portal — browser SPA

Verdict

#5

SPA, localStorage refresh

Public SPA (browser, PKCE)
access TTL10 min
refresh TTL14d absolute · 12h idle
rotationyes
reuse detectyes
storagebrowser localStorage
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Analytics dashboard — browser SPA

Verdict

#6

logout = client-side only

Confidential web app (server-side)
access TTL15 min
refresh TTL30d absolute · 24h idle
rotationyes
reuse detectyes
storageserver-side session store (never reaches the browser)
logout revokeno
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Employee web app — server-rendered

Verdict

#7

read-only widget, god scope

Public SPA (browser, PKCE)
access TTL10 min
refresh TTL14d absolute · 12h idle
rotationyes
reuse detectyes
storagehttpOnly + Secure + SameSite cookie
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile admin:* write:all
audiencenone (any resource)

context: Embeddable read-only status widget

Verdict

#8

BFF, refresh stays server-side

Confidential BFF (backend-for-frontend)
access TTL15 min
refresh TTL30d absolute · 24h idle
rotationyes
reuse detectyes
storageserver-side session store (never reaches the browser)
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Web app via a backend-for-frontend; browser only holds an httpOnly session cookie

Verdict

#9

rotation, silent on replay

Public SPA (browser, PKCE)
access TTL10 min
refresh TTL14d absolute · 12h idle
rotationyes
reuse detectno
storagehttpOnly + Secure + SameSite cookie
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Customer portal — browser SPA

Verdict

#10

mobile, secure enclave

Native mobile app (PKCE)
access TTL15 min
refresh TTL60d absolute · 720h idle
rotationyes
reuse detectyes
storageplatform secure storage (Keychain / Keystore)
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Banking mobile app — long-lived login expected

Verdict

#11

token good at any API

Confidential web app (server-side)
access TTL10 min
refresh TTL30d absolute · 24h idle
rotationyes
reuse detectyes
storageserver-side session store (never reaches the browser)
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceany (no aud / resource)

context: App that calls the billing API, but the token is accepted by payroll and HR APIs too

Verdict

#12

confidential, 8h access

Confidential web app (server-side)
access TTL8 h
refresh TTL30d absolute · 24h idle
rotationyes
reuse detectyes
storageserver-side session store (never reaches the browser)
logout revokeyes
breach revokeyes (kill-switch)
scopeopenid profile offline_access
audienceapi.northwind.com

context: Internal reporting app; access tokens are stateless JWTs with no introspection

Verdict

#13

service-to-service

Machine client (client-credentials grant)
access TTL1 h
refresh TTLnone issued
rotationn/a
reuse detectn/a
storagen/a — no refresh token issued
logout revokeyes
breach revokeyes (kill-switch)
scopeinvoices:read
audienceapi.billing.internal

context: Backend batch job calling an internal API with its own client credentials

Verdict

#14

no breach kill-switch

Confidential web app (server-side)
access TTL15 min
refresh TTL30d absolute · 24h idle
rotationyes
reuse detectyes
storageserver-side session store (never reaches the browser)
logout revokeyes
breach revokeno
scopeopenid profile offline_access
audienceapi.northwind.com

context: Healthcare records app; a stolen-laptop breach was just reported

Verdict

Catch rate vs. false positives

Call each setup, then grade. So far 0/14 decided, 0/10 defects caught, 0 false positive(s).

How it is scored

Catch rate = broken configs given the exact right finding.

A false positive (flagging a sound config) takes an extra hygiene bite — an alert queue that cries wolf is as useless as one that misses.

Harder tiers add subtler setups and deliberate traps (secure-enclave mobile stores, refresh-less services, short stateless JWTs, long-but-bounded remember-me).

Live arena

4 active
adversary kill-chain1/4
sec-analyst-kim19%
authz-dana8%
iam-eng-rao4%
iam-eng-you (you)0%

adversary staging…

TL;DR

What this lab is

  • A free, browser-based token-lifecycle lab: work a queue of ~20 OAuth 2.0 / OIDC token setups and call each one sound or name its single lifecycle defect.
  • Defects seeded across the queue: access-token lifetime too long, refresh token with no absolute expiry, no refresh-token rotation, rotation without reuse detection (no family revoke), refresh token in XSS-reachable storage, no server-side revocation on logout or breach, and over-broad scope with no audience restriction.
  • You are graded on catch rate weighed against false positives — flagging a sound config takes an extra hygiene penalty, because an alert queue that cries wolf is as useless as one that misses.
  • Difficulty tiers add subtler setups and deliberate traps: a secure-enclave mobile store, a client-credentials service that issues no refresh token on purpose, a short-lived stateless JWT with no revocation endpoint, and a long-but-bounded remember-me refresh.
  • The security content follows the real standards — RFC 6749, RFC 9700 (OAuth 2.0 Security BCP), RFC 7009 (revocation) and RFC 8707 (resource indicators) — and after grading every setup shows why the right call is right.

Frequently asked questions

What is the Token Lifecycle Lab?

A free, in-browser exercise where you work a queue of OAuth 2.0 / OIDC token-handling configurations — client type, access- and refresh-token lifetimes, refresh-token rotation, reuse detection, where the refresh token is stored, revocation on logout and breach, and the granted scope and audience — and give each one a verdict: sound, or the specific lifecycle defect. You are scored on how many real defects you catch with the exact right finding versus how many sound configs you wrongly flag.

What token-lifecycle decisions does it teach?

The real ones: access tokens should be short-lived (minutes) because they usually cannot be revoked individually, while refresh tokens are longer-lived but must have a hard absolute cap; public-client refresh tokens must rotate on every use, and a replayed rotated token signals theft and must revoke the whole token family; refresh tokens must never sit in localStorage or a non-httpOnly cookie where XSS can read them; logout and breach response must revoke tokens server-side, not just client-side; and tokens should carry least-privilege scope bound to a single audience/resource so one leaked token is not accepted everywhere.

Does it talk to a real identity provider?

No. Nothing is uploaded, no token is minted, and there is no network or crypto call. The scenarios are authored, realistic token-handling configurations bundled with the page, each with one ground-truth verdict grounded in RFC 6749, RFC 9700, RFC 7009 and RFC 8707. It runs entirely in your browser — no account, no install, nothing sent anywhere.

Who is it for?

Platform, identity and application engineers who design auth flows, security engineers reviewing OAuth/OIDC integrations, and anyone prepping for a security or backend interview who wants to feel why a 24-hour access token, a never-expiring refresh token, rotation without reuse detection, or a refresh token in localStorage are findings — and why a secure-enclave mobile store, a refresh-less client-credentials service and a short stateless JWT are not.

🎉 New here? Use code WELCOME10 for 10% off any plan at checkout
Token Lifecycle Lab — Free Interactive OAuth / OIDC Trainer · PlayCISO