Prerequisites
- Target system, dependencies and environment configured.
Usage
Purpose
A token is a bearer credential — whoever holds it is treated as the user. That makes the whole lifecycle security-critical: how long it lives, where it's stored, how it's refreshed, and — the part everyone underestimates — how it's revoked. This skill covers designing a token lifecycle where theft has a short window and revocation actually works, rather than tokens that stay valid long after they should.
When to use it
Designing or reviewing token-based auth (OAuth2/OIDC access + refresh tokens, API tokens, session tokens). It ties together threads from the OAuth2, JWT, and session skills into the end-to-end question: from issue to death, can a token be misused?
The lifecycle stages
- Issuance — what's in the token, how long it's valid, what it's scoped to.
- Storage — where the client keeps it (and how exposed that is).
- Use — how it's presented and validated on each request.
- Refresh — how a short access token is renewed without re-login.
- Revocation — how a token is killed before its natural expiry.
Procedure
- Keep access tokens short-lived. A short expiry (minutes to an hour) means a stolen access token has a small window. This is the cheapest, most effective control — it bounds the damage of theft without requiring perfect revocation.
- Use refresh tokens for continuity, and rotate them. A longer-lived refresh token gets new access tokens. Rotate it on each use (issue a new refresh token, invalidate the old) and detect reuse of an old one as a theft signal — reuse means someone has a stolen copy, so revoke the whole chain.
- Store tokens with the right exposure in mind. Tokens reachable by JavaScript (
localStorage) are one XSS from theft; prefer secure, httpOnly cookies for session-like tokens, or platform secure storage on mobile. Never put a token in a URL.
- Design real revocation. Self-contained JWTs are valid until they expire — you can't un-issue one — so short lifetimes plus a revocation mechanism (a checked denylist, or short-lived tokens backed by a session the server can kill) are how you actually cut access. Confirm logout, password change, and de-provisioning invalidate tokens promptly.
- Scope tokens narrowly. Least-privilege scope and audience so a leaked token does the minimum, and can't be replayed against a different service.
- Test the gaps: does an expired token still work (validation not checking
exp)? Does logout leave the token usable? Does a rotated refresh token's predecessor still work? Does password change kill existing tokens?
Cheatsheet
lifecycle design
issuance short-lived access token (mins-1h), narrow scope + audience
storage httpOnly secure cookie / secure platform storage
NOT localStorage (XSS-exfiltratable), NEVER in a URL
use validate signature + exp + aud on every request
refresh longer-lived refresh token, ROTATE on each use,
detect reuse of old token -> theft -> revoke the chain
revocation logout / password change / de-provision -> tokens die promptly
the JWT revocation reality
self-contained JWTs can't be un-issued -> valid until exp
=> short lifetimes + a revocation path (denylist or server-side session)
tests
expired token accepted? logout leaves token valid?
old (rotated) refresh token still works? pw-change kills tokens?
Reading the design
- Long-lived access tokens = a stolen token works for hours or days; the single biggest lifecycle weakness. Shorten them and lean on refresh.
- No refresh-token rotation / reuse detection = a stolen refresh token grants indefinite access silently. Rotation plus reuse-detection turns theft into a detectable, revocable event.
- Tokens in
localStorage = XSS becomes full token theft. Move session tokens to httpOnly cookies.
- JWTs treated as revocable when they aren't = a false sense of control; logout "works" in the UI but the token still validates. Add short lifetimes and a real revocation path.
- Password change that doesn't invalidate tokens = a compromised account whose owner resets the password is still accessible to the attacker via existing tokens. Kill them on credential change.
The fix
- Short access-token lifetimes + rotating refresh tokens with reuse detection — the core pattern. Short windows bound theft; rotation makes stolen refresh tokens detectable and killable.
- Store tokens out of JavaScript's reach (httpOnly secure cookies / secure mobile storage), never in URLs.
- Provide genuine revocation: back tokens with a server-side session you can terminate, or maintain a checked denylist, so logout / password change / de-provisioning actually cut access. Accept that self-contained JWTs need short lifetimes precisely because they can't be un-issued.
- Scope narrowly (least privilege, correct audience) to limit what a leaked token can do and prevent cross-service replay.
- Invalidate on the events that matter: logout, password/credential change, role downgrade, suspected compromise.
Pitfalls
- Long-lived access tokens "for convenience". Convenience for the attacker too — theft stays useful for a long time. Short + refresh instead.
- Refresh tokens without rotation. A stolen one is a permanent, silent backdoor. Rotate and detect reuse.
- Assuming a JWT can be revoked by "logging out". It can't be un-issued; without short lifetimes or a denylist, it keeps validating.
- Tokens in localStorage or URLs. XSS-exfiltratable and log-leaking respectively. Use httpOnly cookies / secure storage.
- Not killing tokens on password change. The reset that's supposed to lock an attacker out leaves them in via existing tokens.
References
- OAuth 2.0 Security BCP (RFC 9700) — refresh token rotation, short-lived tokens
- OWASP JWT and Session Management Cheat Sheets
- RFC 7009 (OAuth Token Revocation)
- CWE-613 (Insufficient Session Expiration), CWE-522
Inputs
- Relevant source code, logs, network traces, or system specifications.
Outputs
- Analysis findings, security audit report, or generated code artifacts.
1---2name: token-lifecycle3description: Use when designing how access and refresh tokens are issued, stored, refreshed, and revoked — closing the gaps that let stolen or stale tokens keep working.4---5678## Prerequisites9- Target system, dependencies and environment configured.1011## Usage12### Purpose1314A token is a bearer credential — whoever holds it is treated as the user. That makes the whole lifecycle security-critical: how long it lives, where it's stored, how it's refreshed, and — the part everyone underestimates — how it's revoked. This skill covers designing a token lifecycle where theft has a short window and revocation actually works, rather than tokens that stay valid long after they should.1516### When to use it1718Designing or reviewing token-based auth (OAuth2/OIDC access + refresh tokens, API tokens, session tokens). It ties together threads from the OAuth2, JWT, and session skills into the end-to-end question: from issue to death, can a token be misused?1920### The lifecycle stages21221. **Issuance** — what's in the token, how long it's valid, what it's scoped to.232. **Storage** — where the client keeps it (and how exposed that is).243. **Use** — how it's presented and validated on each request.254. **Refresh** — how a short access token is renewed without re-login.265. **Revocation** — how a token is killed before its natural expiry.2728### Procedure29301. **Keep access tokens short-lived.** A short expiry (minutes to an hour) means a stolen access token has a small window. This is the cheapest, most effective control — it bounds the damage of theft without requiring perfect revocation.312. **Use refresh tokens for continuity, and rotate them.** A longer-lived refresh token gets new access tokens. Rotate it on each use (issue a new refresh token, invalidate the old) and detect reuse of an old one as a theft signal — reuse means someone has a stolen copy, so revoke the whole chain.323. **Store tokens with the right exposure in mind.** Tokens reachable by JavaScript (`localStorage`) are one XSS from theft; prefer secure, httpOnly cookies for session-like tokens, or platform secure storage on mobile. Never put a token in a URL.334. **Design real revocation.** Self-contained JWTs are valid until they expire — you can't un-issue one — so short lifetimes plus a revocation mechanism (a checked denylist, or short-lived tokens backed by a session the server can kill) are how you actually cut access. Confirm logout, password change, and de-provisioning invalidate tokens promptly.345. **Scope tokens narrowly.** Least-privilege scope and audience so a leaked token does the minimum, and can't be replayed against a different service.356. **Test the gaps:** does an expired token still work (validation not checking `exp`)? Does logout leave the token usable? Does a rotated refresh token's predecessor still work? Does password change kill existing tokens?3637### Cheatsheet3839```40lifecycle design41 issuance short-lived access token (mins-1h), narrow scope + audience42 storage httpOnly secure cookie / secure platform storage43 NOT localStorage (XSS-exfiltratable), NEVER in a URL44 use validate signature + exp + aud on every request45 refresh longer-lived refresh token, ROTATE on each use,46 detect reuse of old token -> theft -> revoke the chain47 revocation logout / password change / de-provision -> tokens die promptly4849the JWT revocation reality50 self-contained JWTs can't be un-issued -> valid until exp51 => short lifetimes + a revocation path (denylist or server-side session)5253tests54 expired token accepted? logout leaves token valid?55 old (rotated) refresh token still works? pw-change kills tokens?56```5758### Reading the design5960- **Long-lived access tokens** = a stolen token works for hours or days; the single biggest lifecycle weakness. Shorten them and lean on refresh.61- **No refresh-token rotation / reuse detection** = a stolen refresh token grants indefinite access silently. Rotation plus reuse-detection turns theft into a detectable, revocable event.62- **Tokens in `localStorage`** = XSS becomes full token theft. Move session tokens to httpOnly cookies.63- **JWTs treated as revocable when they aren't** = a false sense of control; logout "works" in the UI but the token still validates. Add short lifetimes and a real revocation path.64- **Password change that doesn't invalidate tokens** = a compromised account whose owner resets the password is still accessible to the attacker via existing tokens. Kill them on credential change.6566### The fix6768- **Short access-token lifetimes + rotating refresh tokens** with reuse detection — the core pattern. Short windows bound theft; rotation makes stolen refresh tokens detectable and killable.69- **Store tokens out of JavaScript's reach** (httpOnly secure cookies / secure mobile storage), never in URLs.70- **Provide genuine revocation**: back tokens with a server-side session you can terminate, or maintain a checked denylist, so logout / password change / de-provisioning actually cut access. Accept that self-contained JWTs need short lifetimes precisely because they can't be un-issued.71- **Scope narrowly** (least privilege, correct audience) to limit what a leaked token can do and prevent cross-service replay.72- **Invalidate on the events that matter**: logout, password/credential change, role downgrade, suspected compromise.7374### Pitfalls7576- **Long-lived access tokens "for convenience".** Convenience for the attacker too — theft stays useful for a long time. Short + refresh instead.77- **Refresh tokens without rotation.** A stolen one is a permanent, silent backdoor. Rotate and detect reuse.78- **Assuming a JWT can be revoked by "logging out".** It can't be un-issued; without short lifetimes or a denylist, it keeps validating.79- **Tokens in localStorage or URLs.** XSS-exfiltratable and log-leaking respectively. Use httpOnly cookies / secure storage.80- **Not killing tokens on password change.** The reset that's supposed to lock an attacker out leaves them in via existing tokens.8182### References8384- OAuth 2.0 Security BCP (RFC 9700) — refresh token rotation, short-lived tokens85- OWASP JWT and Session Management Cheat Sheets86- RFC 7009 (OAuth Token Revocation)87- CWE-613 (Insufficient Session Expiration), CWE-5228889## Inputs90- Relevant source code, logs, network traces, or system specifications.9192## Outputs93- Analysis findings, security audit report, or generated code artifacts.