Session policy and sign-out behaviour
How long a session lasts, what ends one, what a user experiences at each boundary, and why suspending an account does not sign anybody out.
A session is the state that lets somebody keep using the console without typing their password again. Sessions are the part of an identity system people notice only when they are wrong: too short and everyone is irritated all day, too long and a laptop left on a train stays signed in for a fortnight.
This article gives the real numbers, what ends a session, what the person sees at each boundary, and the two administrative actions whose effect on sessions surprises people.
The numbers
| Setting | Value | What it means in practice |
|---|---|---|
| Access token lifetime | 15 minutes | The short-lived credential attached to each request. It is renewed silently in the background; nobody sees this boundary. |
| Idle timeout | 30 minutes | Thirty minutes with no request at all ends the session. Activity is stamped on every authenticated request, so a session in use never idles out. |
| Refresh token / session lifetime | 7 days by default, but now genuinely capped shorter by an enforced session-lifetime policy rule — 8 hours on the seeded default policy | The outer limit of a session. A session now actually ends at whichever is shorter: the platform's 7-day ceiling, or your organisation's configured session lifetime. |
| Concurrent sessions per user | 5 | A sixth sign-in displaces the oldest session. Somebody who works across a desktop, a laptop and a phone will not notice; somebody who never closes anything eventually will. |
In ordinary use — a working day with lunch in it — the thirty-minute idle timeout is still the boundary you meet most often. But do not assume a session survives to the old seven-day ceiling any more: on a tenant running the seeded default policy, it now ends at eight hours.
Session lifetime and re-authentication are now enforced — this corrects an earlier version of this article
Refresh continues to work as described below, with one addition: a rotation now carries the same lifetime and re-authentication deadline forward, and is refused — the session deleted — once the lineage's own lifetime has been reached, distinct from an ordinary expired or reused refresh token.
What ends a session
Six things, and only one of them is the person choosing to leave.
- Signing out
- The session is removed. The next request on it fails the session check rather than merely expiring later.
- Thirty minutes idle
- Checked on every authenticated request. When the last activity is older than the timeout the session is deleted and the request is refused.
- The session lifetime elapses
- Whichever is shorter: the platform's 7-day ceiling, or your organisation's configured session-lifetime rule (8 hours on the seeded default policy). The refresh credential is refused and the session is deleted rather than merely allowed to expire quietly.
- Revoking it
- Either the person revoking their own session from their session list, or an administrator revoking somebody else's. Both delete the row, which takes effect on that session's next request.
- Being displaced
- A sixth concurrent session removes the oldest.
- A password change
- Changing your own password, or having an administrator reset it, deletes all of that user's sessions. See below.
A person can see and manage their own sessions: each one shows the browser identification, the address it was created from, and when. There is a control to end one and a control to end all of them. An administrator can end every session belonging to another member of the organisation, which requires users:write.
Refresh credentials carry the session identifier alongside the secret, and a refresh credential presented after it has already been used is detected and recorded in the audit log as auth.token_reuse_detected. That is the signature of a stolen credential being replayed, and it is worth an alert rule of your own.
What the person actually experiences
| Boundary | What the person sees | What the API returns |
|---|---|---|
| Access token expires, 15 minutes | Nothing. It is renewed in the background. | — |
| Idle for 30 minutes | The next click returns them to the sign-in screen. | HTTP 401 with {"error":"session idle timeout"} |
| Session revoked or already gone | The same — back to the sign-in screen, immediately rather than at the next quarter hour. | HTTP 401 with {"error":"session expired"} |
| Refresh after the session lifetime has elapsed, or with a stale credential | A password prompt. | HTTP 401 with invalid or expired refresh token |
| A malformed refresh credential | The same. | invalid refresh token format |
Note that the first two are served as plain text rather than as the structured error shape the rest of the API uses. If you are writing a client, do not assume a 401 from these paths will parse as JSON. It is an inconsistency in our own error handling and it is on the list to fix.
One thing you will not find is a cookie setting. Sessions here are bearer-token based — the credentials are returned in the response body and held by the client — so there is nothing to configure about cookie flags, and a browser's own cookie controls have no effect on how long somebody stays signed in.
Suspending an account does not sign anybody out
The same applies to clearing somebody's second factor: the enrolment goes, the sessions stay. And to a role change — a session issued while somebody held the admin role does not lose its permissions the moment you change the role, because permissions are resolved from the membership on each request but the session itself persists.
The deprovisioning flow has an explicit option to revoke sessions, and you should use it. Read User lifecycle and deprovisioning before you run it, because it has a second effect that surprises people.
Change the account state
Set the account to locked or suspended, or run the deprovisioning flow. This stops any new sign-in.
Revoke every session
From the member's record, end all of their sessions. Until you do, an open laptop is still an open laptop.
Revoke or reissue their programmatic credentials
An API token continues to work independently of any session. See API tokens — and read the warning there about the blast radius of the deprovisioning flow before you use it.
Check the audit trail afterwards
The status change is recorded as
user.status_changedwith you named as the actor, and session revocation is recorded separately. That record is what you will want in six months when somebody asks who did what.
Password changes, and what they end
Both routes to a new password end every session the account has. When somebody changes their own password they must supply the current one, and on success all of their sessions are removed so every device signs in again. When an administrator resets somebody else's password the same happens to the target account.
There is a restriction on the administrative reset that catches people out: an administrator cannot use it on their own account. The request is refused. To change your own password, use the ordinary change-password route with your current password. If you have forgotten it, use the account recovery flow — which has its own tight rate limit, described in Password policy and lockout.
Password reuse is checked on both routes and refused with cannot reuse a recent password, and the rejection is audited. That is a deliberate friction point: the most common response to a forced reset is to cycle back to the previous password, which returns the account to exactly the state that prompted the reset.
What to do with all this
- Treat thirty minutes idle as your effective session length when you write anything down for an auditor. It is the boundary people meet, and it is not configurable today.
- Pair every account suspension with a session revocation, as one action in your own runbook rather than as two steps somebody may forget under pressure.
- Watch for
auth.token_reuse_detectedin your audit log. It has few innocent explanations. - A global session lifetime and re-authentication interval are now real controls — see the correction above — but they are set on the global session policy, not per group. If a shorter session for one specific group of people is what you actually need, that finer-grained targeting is not available yet; a session-lifetime rule applies organisation-wide.
- A bare
require_reauth: truewith no interval is still inert. If you want re-authentication enforced, give it an actual number.
If a shorter session is a genuine requirement for your organisation, set a session-lifetime rule on the global session policy — it is now enforced, organisation-wide. If what you actually need is a shorter session for one specific group rather than everyone, that finer targeting is not available yet; say so when you talk to us rather than assuming a per-group setting exists.