Ending sessions
This page helps you end a user’s session, and know what that cuts off.
A session ends in one of four ways: someone ends it from the admin console or the API, the user signs out, the user’s credentials change, or a different user signs in on the same browser. And when an app redeems an authorization code twice, the auth server ends the session the code came from if it had refresh tokens to revoke: see auth_code_reuse_detected in the audit log. Each is a security action rather than housekeeping, so each one decides what happens to the tokens the session handed out. A session that merely expires is different: it revokes nothing.
End a session
Section titled “End a session”-
Find the session. A user sees their own under Account, Sessions in the admin console. An administrator sees a user’s on the user’s Sessions tab, and every session signed in to a client on the client’s User sessions tab.
-
Choose End session beside it, and confirm.
The same goes through the API: an administrator calls
DELETE /api/v1/admin/user-sessions/{id}, and a user callsDELETE /api/v1/account/sessions/{id}for one of their own. -
The browser that held the session has to sign in again, and the tokens the session handed out stop working, as below.
What ending a session revokes
Section titled “What ending a session revokes”| What | What happens |
|---|---|
| The session | It’s deleted. The browser that held it has to sign in again |
| Refresh tokens from it | Revoked, offline ones included |
| Authorization codes from it | Revoked, so a code that was issued but not redeemed yet can’t be exchanged |
| The user’s other sessions | Untouched |
That’s what sets ending a session apart from one expiring. An offline refresh token is meant to outlive the session it came from, so it keeps working when that session times out. Ending the session revokes it on purpose.
Each one leaves two entries in the audit log: terminated_user_session, which records what was revoked, and deleted_user_session, the record that the session is gone. Count terminated_user_session to know how many sessions were ended.
A sign-in under way
Section titled “A sign-in under way”A sign-in can’t slip past an ended session. If someone was partway through signing in to an app on the strength of the session you ended, the sign-in goes back to the password step rather than quietly starting a new session. That holds on the consent screen too: just before it issues the code, the auth server checks the session again, so a sign-in left waiting there goes back to the password step as well, and so does one whose session timed out while the screen was open.
A silent request can’t show a page, so it gets login_required instead, and your app decides when to send the user to sign in. Two things withhold that error: a client that registered itself is never sent one, and neither is a redirect URI no longer registered on the client. A silent request that doesn’t come back is then the signal. See The app gets no error back.
Signing out
Section titled “Signing out”Your app signs a user out by sending them to /auth/logout. Signing out revokes nothing: no refresh token and no authorization code is revoked. What it ends depends on what the request carries:
- With an
id_token_hint, the auth server removes your app from the session the hint names. The session itself ends only when no other client is using it, so the user stays signed in to the others. - Without one, once the user confirms on the sign-out page, the whole session ends.
Either way the browser’s cookie is cleared, so its next sign-in starts from the password. A normal refresh token stops working once the session behind it has ended. Offline refresh tokens aren’t tied to a session and keep working.
A sign-out with a confirmed hint leaves deleted_user_session_client in the audit log, for your app leaving the session, and also logout when yours was the session’s last client and the session ended. One without a hint leaves logout, even when there was no session, and deleted_user_session when there was one.
Credential changes
Section titled “Credential changes”When a user’s credentials change, their sessions and refresh tokens stop being usable:
| Action | What happens | reason |
|---|---|---|
| The user resets a forgotten password | Every session of theirs is ended and every refresh token revoked | password_reset |
| The user changes their own password | The same, except the session they’re changing it from | password_change |
| An administrator sets the user’s password | Every session of theirs is ended and every refresh token revoked | admin_password_set |
| An administrator disables the user | The same. Enabling them again doesn’t bring the sessions back | account_disabled |
That covers every grant, offline refresh tokens whose session has already expired and tokens from the password grant included, and an authorization code that was issued but not redeemed yet can’t be exchanged any more. Each change leaves a revoked_user_auth_state entry in the audit log, with the reason above and the sessions and refresh tokens it ended.
A user changing their own password normally stays signed in to the app they did it from. If that app refreshes at the same moment as the change, it may be asked to sign in again.
These end nothing:
- Changing an email address. The change already asks for the current password, so signing other devices out would protect nothing that person couldn’t do again. Tokens issued before it carry the old
emailclaim until they’re refreshed or expire. - Setting up or removing two-factor authentication. Each session is checked again for a second factor before it’s used for a level above
urn:goiabada:level1, and removing it also lowers each session to what a password alone reaches. See ACR and AMR. For a lost or stolen device, end the user’s sessions as well: see A user who lost their authenticator.
A different user signs in on the same browser
Section titled “A different user signs in on the same browser”A shared or borrowed browser can reach the sign-in page still holding someone else’s session. That happens whenever a client sends prompt=login or an id_token_hint naming another user, and whenever the session there has stopped being valid.
When the person who signs in is a different user, the browser has changed hands:
| What | What happens |
|---|---|
| The previous user’s session | Ended, as if someone had ended it: deleted, with its refresh tokens and unredeemed authorization codes revoked |
| The new user | Gets a session of their own, never the one that was there |
| The previous user’s other devices | Untouched. Only what this browser’s session handed out is revoked |
The grants that session held were reachable from this browser, and the browser is now someone else’s. An offline refresh token from it would otherwise keep working in the background indefinitely.
Nothing carries over. If the client asks for a one-time code, the new user is asked for one, however the previous user signed in, and the acr and amr in their tokens describe only what they did.
Each handover leaves a cross_user_session_replaced entry in the audit log, naming both users and the session that was ended, beside the terminated_user_session and deleted_user_session entries for that session and the started_new_user_session entry for the new one. It’s the entry that tells a browser changing hands apart from an administrator ending a session.
What it doesn’t reach
Section titled “What it doesn’t reach”An access token is checked by signature, and an API doesn’t ask the auth server about it, so nothing on this page can take back one already issued:
- The auth server’s own endpoints,
/userinfoand the Admin and Account APIs, refuse an access token whose session has ended or expired, or whose user was disabled or changed their credentials, on the very next request. - An access token from an offline grant carries no
sid, so ending the session it came from doesn’t reach it, even at the auth server’s own endpoints. A credential change does. - Your own APIs, checking the signature alone, accept the token until it expires.
That’s inherent to signed tokens, and it’s the main reason to keep access tokens short-lived: the token lifetime, 5 minutes in a new install, is the longest a token can outlive any of this.