Skip to main content

Signed out unexpectedly

Session lifetime, the idle timeout, what invalidates a session, the home-region refusal, and the multi-organisation limitation behind a 403.

Written for whoever runs IT10 min readUpdated

People are being signed out and nobody changed anything. There are six causes and they are easy to tell apart once you know what to look for: the idle timeout, the refresh cycle, something that deliberately invalidated the session, the concurrent-session cap, the wrong regional address, and one limitation that affects only people who belong to more than one organisation.

The numbers that actually apply

The session and token values in force. All are fixed in code; none is configurable per organisation.
ValueSettingWhat happens when it is reached
Access token lifetime15 minutesThe client silently exchanges its refresh token for a new one. A person should never notice this.
Refresh token lifetime7 daysAfter a week without use, a fresh sign-in is needed.
Idle timeout30 minutesThe session record is deleted and the next request answers 401 {"error":"session idle timeout"}.
Concurrent sessions per person5A sixth sign-in evicts the oldest session. That older device is signed out.

The two idle-related refusals to match against are {"error":"session idle timeout"} — the session existed and had been quiet too long — and {"error":"session expired"}, which means the session record could not be found at all, usually because something deleted it. Both are 401, and both are written with the plain error helper, so the body is JSON while the header claims text/plain.

What the person actually sees

Worth knowing before you answer a ticket, because it is no longer the bare sentence it once was. Somebody bounced to the sign-in screen because their session expired is given a plain explanation there rather than being dropped at an ordinary sign-in form with no context.

Your session expired. You were signed out after a period of inactivity. Sign in again to carry on where you left off.
The explanation shown on the sign-in screen after an expiry

If they were on a particular page when it happened, the sign-in screen also says so plainly — it tells them they will be taken back to that same page once they have signed in, and shows the address. And it does: after signing in they land back on the screen they were using, rather than at the overview. So carry on where you left off is a description of the behaviour rather than a figure of speech.

None of this tells you why the session ended. The screen is the same for an idle timeout, an evicted session, an administrative revocation and a deliberate invalidation, so the rest of this article is still how you tell them apart.

What invalidates a session on purpose

Each of these ends sessions deliberately, and the affected person will be signed out immediately rather than at the next expiry.

The person changes their own password
All of their sessions are ended, on every device, not just the one they used to make the change. Audited as auth.password_changed. This is standard and correct — a password change is often a response to a suspicion, and leaving the other devices signed in would defeat it.
An administrator resets somebody's password
The target's sessions are all ended. Two audit rows are written, one against the administrator (auth.admin_password_reset) and one against the person (auth.password_reset_by_admin), so the trail names both parties. Note an administrator cannot reset their own password this way — the endpoint refuses when the actor and target are the same.
An administrator revokes sessions directly
DELETE /api/v1/organizations/{orgID}/users/{userID}/sessions, requiring the users:write permission. The blunt instrument, and the right one when a laptop is lost.
The organisation is suspended or deprovisioned
Every member's sessions are ended and every API key in the organisation is revoked. This is the widest-reaching action in the product; see the caution below.
A refresh token is presented twice
Refresh tokens are single-use. A second presentation of the same one is treated as a possible theft and every session for that person is deleted, audited as auth.token_reuse_detected. A client with a race condition that refreshes twice in parallel will therefore sign its own user out. If a particular integration signs itself out under load, this is the first thing to check.
A user is deprovisioned
Sessions are revoked and the account is deactivated. Be aware that deprovisioning also revokes every API key in the whole organisation, not just the departing person's. That is a defect and it is documented in User lifecycle and deprovisioning; check it before you deprovision anybody mid-week.

The residency check, for completeness

Your organisation is bound to a home region. A request that arrives at a different region is refused rather than served, whether or not the credentials are good, with HTTP 451. This is not a live cause of a real sign-out today: Qorionix runs one production cell, hosted in the EU (Ireland), so there is no second region to land on by mistake.

The shape of a cross-region refusal, were there a second region to refuse into
HTTP/1.1 451 Unavailable For Legal Reasons
X-Qorionix-Home-Region: eu-central-1

{
  "error": "tenant home_region does not match this cell",
  "home_region": "eu-central-1",
  "cell_region": "eu-central-1"
}

The region is stamped into the session token at sign-in and compared against the region the server is running in — the check does not trust the address you came in on. GET /api/v1/region tells you which region and cell you are talking to, if you need to confirm it.

The multi-organisation limitation

This is the one that generates the most confusing tickets, so it gets its own section. Sessions carry the organisation you are acting in as a claim. For somebody who belongs to exactly one organisation, we fill that claim in automatically at sign-in and everything works.

The two refusals that come out of this are 403 {"error":"token carries no organization"}, from the routes that read the claim — Sentinel-Q, billing, the subject-request queue, OIDC client registration — and 403 {"error":"organization mismatch"}, which means the organisation in the address is not the one the credential belongs to. The second one is what you get if you paste a URL for the organisation the console did not pick.

What you can actually do about it today, in order of preference:

  1. Use a separate account per organisation. Unattractive, and completely effective. One address per organisation, each with exactly one membership. This is what we recommend until a selector exists, and it is the only option that makes every route work.
  2. Do the affected work from a single-organisation account. If you administer three tenants but only configure billing on one, hold that one on a dedicated login.
  3. Know which organisation the console chose. It is the first membership returned by GET /api/v1/users/me/organizations. If somebody with several memberships reports that a setting they made has vanished, they very likely made it in a different organisation than the one they are looking at now.

Two further consequences. A person with no memberships at all is shown the shell with no organisation and a licence status of unlicensed, rather than an error — which reads as a broken account and is in fact an empty one. And sign-on policy and risk scoring are organisation-scoped, so somebody with several memberships is evaluated against their first organisation's policy: if a person seems exempt from a rule you know you enabled, count their memberships before you re-read the rule.

One thing this is not: a cookie problem

The API is bearer-token based. Tokens come back in the response body and no sign-in cookie is issued. So the usual cookie suspects — a SameSite change, a third-party cookie block, a clock making a cookie look expired — are not in play. If a browser is losing its session and the server-side session is still listed as open, the problem is in how the client stores or sends the token, not in a cookie policy.

A short triage

  1. Ask how long they were away

    Thirty minutes of inactivity ends the session. If they went to lunch, that is your answer and nothing is wrong.

  2. List their open sessions

    GET /api/v1/auth/sessions. More than five devices means the cap is evicting the oldest. Sign the stale ones out deliberately.

  3. Check what changed administratively

    A password reset, a session revocation, an organisation suspension or a deprovisioning all end sessions immediately. The audit log names the action and the actor.

  4. Check the address, not the account

    A 451 means the wrong regional host. Fix the bookmark or the integration's base URL.

  5. Count their memberships

    If a 403 token carries no organization is in the picture, the person is in more than one organisation and you are looking at the limitation above.

  6. If a refresh loop is signing a service out

    Look for two parallel refreshes. A reused refresh token deletes every session for that identity by design.

Was this article wrong?

If a procedure here does not match what you see, or a limit we described has changed, tell us and we will fix the page. Email us about this article, or see how to get help if you need an answer rather than a correction.

Everything in troubleshooting