Support Global Logout with Token Revocation
Track token families or a per-user token version, revoke on logout-everywhere and password change, and validate the version on every request.
Task
Make it possible to invalidate all of a user sessions at once when a credential may be compromised.
When to use this
A user changes their password or reports a stolen device, but existing JWTs stay valid until they naturally expire, so the attacker keeps access.
Prerequisites
- A store for token versions or revocation lists
- A request-time validation hook
Steps
1. Store a per-user token version or a list of active token families.
Expected output: The server can invalidate issued tokens.
2. On logout-everywhere or password change, bump the version or revoke the families.
Expected output: All outstanding tokens become invalid.
3. Validate the token version on each request.
Expected output: Revoked tokens are rejected immediately, not at expiry.
4. Keep access tokens short-lived so revocation windows are small even without a store check.
curl -X POST https://api.example.com/auth/logout-all -H "Authorization: Bearer $TOKEN"Expected output: The blast radius is bounded.
Troubleshooting
Problem
Revocation not enforced
Solution
Check the version or denylist on every request; trusting expiry alone leaves a window.
Problem
Version store unavailable
Solution
Decide fail-open or fail-closed explicitly; for high-risk actions prefer fail-closed with a short cache.
Limitations
- Per-request revocation checks add a store lookup unless access tokens are very short-lived.
- Refresh tokens need their own revocation strategy, usually rotation with reuse detection.
Context
Make it possible to invalidate all of a user sessions at once when a credential may be compromised. A user changes their password or reports a stolen device, but existing JWTs stay valid until they naturally expire, so the attacker keeps access.
Steps
- Store a per-user token version or a list of active token families. Expected: The server can invalidate issued tokens.
- On logout-everywhere or password change, bump the version or revoke the families. Expected: All outstanding tokens become invalid.
- Validate the token version on each request. Expected: Revoked tokens are rejected immediately, not at expiry.
- Keep access tokens short-lived so revocation windows are small even without a store check. Expected: The blast radius is bounded.
const user = await users.get(payload.sub);
if (payload.ver !== user.tokenVersion) {
throw new Unauthorized('token revoked');
}
Verify
- The server can invalidate issued tokens.
- All outstanding tokens become invalid.
- Revoked tokens are rejected immediately, not at expiry.
- The blast radius is bounded.
Limits
- Per-request revocation checks add a store lookup unless access tokens are very short-lived.
- Refresh tokens need their own revocation strategy, usually rotation with reuse detection.