TILLAUTH · FLOWS

SSO session.

GA

Someone who signs in on your hosted pages stays signed in on that browser. The next app that sends them to TillAuth, whether a Sign in with TillAuth client or the hosted pages again, signs them straight in. Nobody types a password twice, and a stolen cookie on its own gets nowhere it shouldn't.

01Model

How it works

  1. The user signs in on the hosted pages with any method the app allows. The page starts an SSO session and keeps its secret in an HttpOnly, Secure, SameSite=Strict cookie on the hosted address. Page script never sees it.
  2. Later, an app sends the browser back. The hosted page swaps the cookie for a one-use code that lasts 60 seconds, and the browser spends that code itself.
  3. The new sign-in is checked like any other: the user must still be active and allowed into the app, and session risk scores it from the browser's own network. Under enforce, an unusual one gets the full sign-in page instead, and a very unusual one is blocked.
  4. The browser gets a session of its own, with its own refresh token. It carries the original sign-in's second factor, so mfa is true only if that sign-in passed one.
One sign-in, many sessions
Every app signed in this way gets a separate session you can see and end on its own. Ending the SSO session ends all of them at once.
02Limits

How long it lasts

It ends whenDetail
Unused for the idle limit168 hours (7 days) by default. Each sign-in through it starts the idle clock again.
The absolute limit passes720 hours (30 days) by default, counted from when the user actually signed in. Using it, or signing in through it, never extends it.
The sign-in behind it endsSigning out, a password change or reset, ending sessions from the dashboard, CLI or API, a SCIM deactivation, token theft detection and the session-risk policy all end it.
The user signs out everywhereSigning out on the hosted pages ends the SSO session, the sign-in it came from and every session it started.

A shorter limit you set later applies to SSO sessions already running. Turning SSO sessions off stops them being used at once; turning them back on lets the ones still within their limits work again.

03Configure

The policy

SSO sessions are on for every app. Change them on the app's Policies page, from a terminal, or through the API. Limits are whole hours from 1 to 2160 (90 days), and the idle limit can't be above the absolute one. Fields you leave out keep their value.

tilldev auth apps update my-app --sso-session on --sso-idle-hours 12 --sso-absolute-hours 168 PATCH https://tilldev.dev/api/auth/admin/apps/<app> { "settings": { "sso_session": { "enabled": true, "idle_hours": 12, "absolute_hours": 168 } } }

The Policies page also shows how many SSO sessions are live, how many sign-ins came through one in the last 7 days, and how many of those risk sent to a full sign-in.

04Clients

With Sign in with TillAuth

Silent sign-in. Add prompt=none to the authorization request to check for a session without showing anything. If the user can't be signed in silently, the browser returns to your redirect_uri with one of these errors and your state. none can't be combined with other prompt values.

errorMeaning
login_requiredNo SSO session on this browser, or it ended, or the sign-in is older than max_age.
interaction_requiredThe user has to set up a second factor first.
consent_requiredThe client needs consent the user hasn’t given yet.

Freshness still holds. The auth_time claim is when the user actually signed in, not when the SSO session was used, so max_age and prompt=login still send someone with an old sign-in back through the full page.

Logout. The end_session_endpoint is now on the hosted pages, so it can reach the cookie. Send the user there with an id_token_hint and they're signed out without a question; without one, or with a hint for a different user, they're asked first. A hint is accepted for 30 days after it was issued, even once expired. Only an ID token works as a hint, never an access token.

GET https://tilldev.dev/oidc/logout ?id_token_hint=<id_token> &post_logout_redirect_uri=https://ops.acme.com/goodbye &state=<state>

The old address, https://auth.tilldev.dev/v1/oidc/logout, redirects there, and the discovery document advertises the new one. A post_logout_redirect_uri must be registered on the client.

05Reference

The endpoints

The hosted pages use four endpoints of the TillAuth API. If you host your own sign-in pages, they let you offer the same thing: keep the secret in an HttpOnly cookie your server sets, and have the browser spend the code itself so the right network is scored.

EndpointDoes
POST /v1/sso/sessionStarts one from a current refresh_token; pass the old secret as replaces to end it. Answers the secret and both end times, or 403 sso_disabled.
POST /v1/sso/grantSwaps the secret for a one-use code. Answers 401 login_required with a state once the session has ended.
POST /v1/sso/tokenSpends the code from the user's browser and answers a session. 401 with reason: "risk" means show the full sign-in page; 403 signin_blocked means blocked.
POST /v1/sso/endEnds it and everything it touched. With expect_sub, a session of a different user is left alone and the answer says mismatch.
06Watch

Where it shows

  • The audit log records sso.session.created, sso.session.used, sso.session.refused and sso.session.ended, and admin.sso_session_changed for policy changes.
  • Sign-ins through it are scored with the method sso, so signin.risk and signin.risk_blocked show where they came from.
  • sso.session.used, sso.session.refused and sso.session.ended can be sent to your webhooks.
07Limits

What it doesn't do

  • It belongs to one browser and one address. The app's tilldev.app address, its custom domain and the Sign in with TillAuth pages each keep their own, and a private window starts with none.
  • It stays inside one app's users. Another TillAuth app never sees it.
  • Apps that sign users in through your own forms and the SDKs don't start one unless you call the endpoints above.
  • A backend that verifies access tokens itself keeps accepting an ended session's tokens until they expire, at most 10 minutes later.