A secure logout does two things: it deletes the tokens on the device, and it asks the authorization server to revoke them. Only the second step makes a copied token stop working. RFC 7009 defines the revocation endpoint for that, and revoking a refresh token should also invalidate access tokens from the same grant.
Why local logout is not enough
If an app only clears its stored tokens, the tokens still exist on the server side as valid credentials until they expire. Anyone who copied them earlier, from a backup, a log, a compromised device or a proxy, can keep using them.
That matters most for refresh tokens, which are long lived. RFC 9700, the OAuth security guidance, notes that refresh tokens are an attractive target because they represent the full scope of access granted to a client and are not constrained to a specific resource. A leaked refresh token that is never revoked can keep minting access tokens.
What RFC 7009 provides
RFC 7009 adds a revocation endpoint to the authorization server. The client sends a POST with a token parameter, an optional token_type_hint of access_token or refresh_token, and its client credentials where it has them. The rules worth knowing:
| Topic | What the RFC says |
|---|---|
| Timing | Invalidation takes place immediately, though there can be a propagation delay across servers |
| Client behaviour | After a 200 response, the client must not try to use the token again |
| Refresh token revoked | The server should also invalidate access tokens based on the same grant, if it supports that |
| Access token revoked | The server may revoke the matching refresh token too |
| Response | 200 if revoked or if the token submitted was invalid |
| Ownership | The server verifies the token was issued to the requesting client |
The 200 for invalid tokens is deliberate. It stops the endpoint from being used to test whether a token is valid.
Steps for a mobile logout
- Revoke the refresh token first, sending token_type_hint refresh_token. This should cascade to access tokens on servers that support it.
- Also revoke the current access token if your server does not cascade, or if it is long lived.
- Delete both tokens from secure storage, and any cached user data that is not needed after logout.
- Clear sensitive state: in memory caches, web view cookies if the app used a browser session, and push notification registration tied to the user.
- If the app uses a system browser session for sign in, decide whether to also end the identity provider session, as covered by single logout options.
- Handle failure. If the revoke call fails because the phone is offline, queue it and retry, and make sure the server side expiry is short enough that the gap is tolerable.
Server side points
- Short access token lifetimes limit the damage when revocation is delayed. Self contained tokens such as JWTs cannot be revoked by a lookup alone, so either keep their lifetime short or check a revocation list for high value operations.
- Make sure the resource server actually honours revocation, for example through introspection or a deny list. A revocation endpoint that nothing consults gives false comfort.
- Revoke on events beyond logout: password change, suspected theft, device removal and account closure.
- Log revocations with the client and user, so you can show when access ended.
Related reading
Safeguard's agent identity capability applies the same idea to automated callers, with issue, scope, expire and revoke as explicit steps, and its asset discovery helps find services that still accept old credentials. A free scan is at gold.safeguard.sh/scan.
Quick check
Does revoking a refresh token kill the access token too?
RFC 7009 says the server should also invalidate access tokens from the same grant, if it supports revoking them. Check your server's behaviour rather than assuming.
Should logout fail if the revoke call fails?
No. Complete the local logout, retry the revoke when possible, and keep server side lifetimes short.
Sources
Last reviewed: 19 October 2026.