Answers · The network and the web
Does signing out actually invalidate my token on the server?
In shortNo. Signing out clears your browser's copy of the token, but the server keeps accepting that token until it expires.
No, not on its own. Signing out deletes the browser's copy of the token; the token itself keeps being accepted by every service that holds it until the expiry printed inside it arrives, or until something explicitly starts refusing it.
Why the server never hears about it
An access token is a signed statement that answers for itself. A service receiving one does two things: it checks the signature against the issuer's key, and it compares the current time with the expiry inside the token. Neither step consults any record that a sign out could have changed. There is no session row on the far side to delete, because the far side was built not to need one. That is the whole point of a self-contained token, and it is also the price.
A token is issued at 15:58 with a five minute lifetime, so . At 16:00 the person signs out and the browser's storage is emptied. At 16:01 the same string, copied from a proxy log an hour earlier, is sent to the API. The signature verifies, , and the request succeeds. At 16:04 the identical string is refused, not because of the sign out, which is four minutes old and irrelevant, but because the clock passed 16:03. The sign out shortened nothing. The remaining lifetime did all the work, and it was three minutes.
| step | time | event | the server's check | result | what happened |
|---|---|---|---|---|---|
| 1 | 15:58 | token issued with a five minute lifetime | nothing yet | the token is live | The expiry is fixed at issue and nothing later can move it. |
| 2 | 15:59 | the string is copied out of storage | not involved | a second copy now exists | Copying is not theft of anything the server tracks; the string is the credential. |
| 3 | 16:00 | the person signs out, storage cleared | signature verifies, 16:00 < 16:03 | accepted | The sign out touched one copy. The server was not told. |
| 4 | 16:01 | replay from another machine | signature verifies, 16:01 < 16:03 | accepted | This is the row people are surprised by. |
| 5 | 16:04 | the same replay again | signature still valid, 16:04 > 16:03 | refused | The refusal came from the clock, not from the sign out. |
Signing out is not pointless. It takes the credential out of reach of page code and of the next person at the keyboard, which stops the browser being the leak. It is simply not revocation, and the list of what it does and does not reach is short enough to keep in view.
| where the credential lives | cleared by signing out | how long it stays usable |
|---|---|---|
| browser cookie or local storage | yes, at once | that copy is gone; other copies are not |
| an access token already issued | no | its own expiry, 16:03 above |
| refresh token record in your store | only if you delete the row | until deleted, or its own expiry |
| cached permission decision in another service | no | that cache's lifetime |
| grant held at an external provider | no | until somebody tells the provider |
The intuition that fails is: the token is in my browser, so deleting it deletes the access. Deleting it deletes your copy of the proof, which is a different object from the proof. Everything that made the string acceptable is still true afterwards. The signature still matches, the claims still describe this person, the expiry has not arrived. Nothing in the acceptance path is told that a copy was destroyed, so nothing updates. The same reasoning explains why clearing a cookie on a phone does not sign the person out on a laptop, and why an attacker who already has a copy is wholly untouched by whatever the user does next.
What actually revokes
Three mechanisms withdraw a self-contained token before its expiry, and each buys back the lookup that self-containment was avoiding. A denylist holds the identifiers that must not be honoured and every accepting service checks it on each request. Introspection makes the service ask the authority whether this token is still good, rather than deciding from the token alone. Short lifetimes plus a revocable renewer are the cheap version: keep the worker's life to a few minutes and make the long renewer a handle looked up in your store, so deleting the row stops the next renewal. The renewer can be withdrawn. The worker cannot, which is exactly why it is short.
The number worth publishing is not how long the sign out request took. With three minutes left on the token at the moment of revocation and a five minute cached authorisation decision sitting behind it in another service, the residual window is the sum, because a service may hold a valid token and a stale yes at the same time.
All of this changes if the token is a handle rather than a statement. An opaque string that means nothing on its own is looked up on every request, so deleting the row is real revocation and the window falls to however long the deletion takes to propagate. The same collapse happens to a signed token the moment every accepting service checks a denylist or asks the authority. What fails is partial adoption: five services consult the list and the sixth, owned by another team and never redeployed, does not, so the token stays valid there for its full remaining lifetime.
So the honest sentence after a sign out has three times in it, and none of them is the moment the delete returned. Access was withdrawn at 16:00, every path under your own control closed at 16:03, and the longest path you do not control, a partner's cached grant, runs to 16:08. Eight minutes, 480 seconds, written down: that is the revocation.
Worth keeping
- A signed access token is accepted on its signature and its expiry alone, so deleting it from a browser changes nothing on the server.
- Revocation is proven only by an observed refusal, never by a delete that returned success.
- The residual window is the remaining token lifetime plus the lifetime of any cached authorisation decision sitting behind it.
Where this goes next
This question is one step of Proving Who You Are, a course that works through its subject from the beginning. The page that teaches this part of it is Taking Access Away, and it reads the whole way through whether or not you have an account.
What an account changes is the practice: problems standing under every idea, marked with a reason rather than a tick, in a copy of the course that is yours.
Read that pageThe whole courseOther questions people ask about this
- Where should a session ID be stored so JavaScript can't read it?Store it in an HttpOnly cookie set by the server; that is the only browser storage JavaScript running on the page cannot read.
- How can another site make a request as me if it can't read my cookies?A foreign page does not need to read your cookie. It makes your browser send a request to the site that owns the cookie, and the browser attaches the cookie automatically.
- Why isn't a password plus a security question really two-factor authentication?A security question is another thing you know, so it is the same kind of proof as a password, not a second kind.
- What does it mean for an API method to be safe?A safe method is one that changes nothing on the server when it is called, so a caller may repeat it freely and a cache or a crawler may use it without anything being altered.
- Why does the TLS handshake take so many round trips before any data is sent?It is not one key exchange. The handshake agrees a secret, proves the server's identity and checks for tampering, and modern TLS fits those into one round trip; a fresh connection still needs three before the page starts.
- If a website has HTTPS, can someone on the same Wi-Fi read my password?No. HTTPS encrypts the form contents and cookies, so someone on the same Wi-Fi cannot read the password itself; they can still see the site, timing and packet sizes.