With a self-contained token used as the API credential, what does logout actually accomplish, and how do you design revocation so that disabling an account takes effect quickly without a lookup on every request?
answer
- Bearer = possession is enough; logout is local
- Short expiry bounds the damage
- The refresh record is the revocable thing
- Token-id denylist (precise) vs token version (broad)
- Revoke on password, role and MFA changes too
basics
~20 sClient-side logout only discards the local copy; a stolen token still works until it expires. Design for it: keep access tokens short-lived, store the refresh credential server-side so it can be deleted, and if you need faster, check a small replicated denylist or a per-user token version.
solid answer
~50 sWith a self-contained token, logout on the client is just deleting the local copy. Any copy an attacker already holds keeps working until the expiry claim, because the API validates the signature and nothing else. So revocation must be designed in, at three levels: 1. **Short access-token lifetime** - minutes. Expiry becomes the revocation bound, with no per-request cost. 2. **Server-side refresh record** - the long-lived credential is stored and revocable. Logout, password change or admin disable deletes it, so no new access tokens are minted and access ends within one access-token lifetime. 3. **Fast-path revocation when minutes are too slow** - a denylist of revoked token ids, or a per-user token-version claim compared against a stored value. Both stay small because entries expire when the token would have anyway, and both can be replicated to instances so the hot path stays local. Also revoke on privilege change, not just logout, and in the cookie case clear it with a server-sent expired Set-Cookie.
go deeper
Say that a self-contained token stays valid until it expires, so logout on the client only removes the local copy; short lifetimes are the basic mitigation.
Add the refresh-token split - the long-lived credential is stored server-side and can be deleted - and explain why that bounds access to one short lifetime.
Present all three layers with their hot-path costs, cover rotation and reuse detection, the full list of revocation triggers, and correct server-side cookie clearing.
Set the acceptable revocation window as an explicit policy per risk tier, weigh the added dependency of a fast-path check against availability, and define the emergency mass-invalidation procedure.
## Why logout is not automatic A self-contained token is a **bearer credential**: possession is sufficient, and validation consults only the signature and the claims. Nothing in a normal validation path asks whether the session still exists. So a client-side logout that clears storage removes the honest user's copy and nothing else. If the token leaked - via XSS, a shared machine, a proxy log, a captured request - the attacker retains working access for the remainder of its lifetime. This surprises people used to server-side sessions, where deleting the record ends access on the next request. ## The design that makes logout meaningful **Layer 1 - short lifetimes.** Access tokens of five to fifteen minutes. The maximum exposure after any revocation event equals the remaining lifetime, and it costs nothing per request. Long-lived access tokens are the root cause of most "we cannot log people out" incidents. **Layer 2 - a revocable refresh credential.** The long-lived credential is recorded server-side, one row per session, with a device or client identifier. Logout deletes that row; log out everywhere deletes all rows for the user; an admin disable does the same. Because refresh happens rarely, the store is touched at a tiny fraction of request volume, so it is not a hot-path dependency. This also enables real features: a session list in account settings, and per-device revocation. Pair it with **refresh-token rotation**: each refresh returns a new refresh token and invalidates the old one. If an old one is presented again, that indicates theft or replay, and the whole family should be revoked. This turns silent compromise into a detectable event. **Layer 3 - immediate revocation when needed.** For high-value systems where even minutes are unacceptable: - **Denylist by token identifier.** Tokens carry a unique id claim. Revocation inserts that id with a lifetime equal to the token's remaining life. The list is inherently small - bounded by revocations within one access-token lifetime - so it can be pushed to every instance and checked in memory. - **Per-user token version.** The token carries a version claim; the user record holds the current version. Bump it and every existing token for that user is invalid at once. This needs the current version available cheaply - a small cache with a short lifetime is usually acceptable, since the staleness window becomes seconds. The denylist is precise (one session) and the version counter is broad (all sessions for a user); many systems implement both. ## Events that must trigger revocation Do not scope this to a logout button. Revoke on password change or reset, on MFA enrolment changes, on role or permission changes (otherwise a demoted user keeps elevated claims until expiry), on account suspension or deletion, and on detected refresh-token reuse. ## The cookie case If the credential travels in a cookie, logout must clear it **server-side** by sending a `Set-Cookie` with the same name, path and domain and an expiry in the past - relying on client JavaScript is unreliable, and an `HttpOnly` cookie cannot be cleared by script at all. Clearing the cookie still does not invalidate a self-contained value someone copied, so the same layered design applies. ## Operational realities Clocks matter: expiry is evaluated against each server's clock, so skew tolerance should be small and time synchronisation mandatory, otherwise "expires in five minutes" quietly becomes longer. Key rotation is not revocation, but retiring a signing key does invalidate everything signed with it, which is the emergency lever for a mass invalidation event - disruptive, and worth having a rehearsed procedure for. ## Interview framing Open with the honest statement that client-side logout does not revoke anything, then present the three layers with their per-request cost, name refresh-token rotation and reuse detection, and list the non-logout events that must also revoke. That sequence demonstrates you have operated such a system rather than only configured one.
- How does refresh-token rotation help detect theft?Each refresh issues a new refresh token and invalidates the previous one, so a given token is usable exactly once. If a previously used token is presented again, either the legitimate client or an attacker is replaying it, which is a strong signal of compromise. The standard response is to revoke the entire token family for that session and force re-authentication.
- Does adding a denylist check on every request mean you have simply rebuilt server-side sessions?Not quite. The denylist is bounded by revocations within one short access-token lifetime, so it stays tiny and can be replicated in memory to every instance, keeping the check local. A session store must hold a record for every active session and be consulted remotely. You keep most of the scaling benefit while shrinking the revocation window to near zero.
saying these in an interview costs you the question
- Believing that deleting the token from client storage revokes it
- Issuing access tokens valid for days and treating expiry as the only revocation path
- Revoking only on explicit logout, ignoring password resets, role changes and account suspension
- Clearing an authentication cookie in JavaScript rather than with a server-sent expired Set-Cookie
- Treating signing-key rotation as a routine per-user revocation mechanism