Revocation
Last updated
Revoke() implements logout: it clears cookies, invalidates the current Access Token immediately, and expires the Refresh ID after 5 seconds.Flow
| # | Step | On failure |
|---|---|---|
| 1 | Send Set-Cookie headers clearing access_token and refresh_id (regardless of what follows) | — |
| 2 | Read the Refresh ID | Missing → 400 data_missing |
| 3 | Read refresh:<id> | Absent → 401 unauthorized; Redis error → 500 failed_to_get |
| 4 | Read its TTL | TTL ≤ 0 → 401 unauthorized |
| 5 | MULTI: set refresh:<id> TTL to 5 seconds and write revoke:<accessToken> (TTL AccessTokenExpires) | 500 failed_to_store |
On success the result is
200 with Success set to true.Example
- mux.HandleFunc("POST /logout", func(w http.ResponseWriter, r *http.Request) {
- result := auth.Revoke(w, r)
- if !result.Success && result.StatusCode >= 500 {
- http.Error(w, result.Error, result.StatusCode)
- return
- }
- w.WriteHeader(http.StatusNoContent)
- })
A
400/401 means the session no longer exists and the cookies are already cleared, which is a completed logout from the user's view, so the example treats only 5xx as an error.Boundaries
| Case | Behavior |
|---|---|
| Refresh ID kept for 5 seconds | Within 5 seconds of revocation, a request carrying the same Refresh ID (for example via X-Refresh-ID) and no Access Token can still refresh |
| Scope | Only the Access Token in the request is invalidated; the same user's sessions on other devices are unaffected |
| No Access Token sent | revoke: is still written (with an empty key), and the Refresh ID still expires |
| Logging out twice | The second call returns 400 data_missing because the cookies are already cleared |
See step 2 of Verification Flow for how a revoked token is rejected.