SSO across your apps

One login for several existing applications, without an SDK or a frontend change.

Useful if you want to…

  • give users one login for several applications;

  • keep the applications untouched: no SDK, no OIDC library, no frontend patch;

  • share a session between app.example.com, reports.example.com and similar hosts;

  • revoke a session centrally and have every application refuse it on the next request.

Gate One is a reverse proxy: the application still receives a normal HTTP request. It never sees a token unless you ask for it.

What the user sees

The first visit to any protected host redirects to the login host. After the identity provider callback, Gate One sets one session cookie on the shared parent domain. Every other Gate One route on that domain accepts the same session, so the user does not log in again.

According to the route, the application receives an identity:

  • X-Gate-One-Subject (opaque, stable per user and issuer) when usage events are enabled;

  • the identity headers configured by the auth provider;

  • the original Authorization header only when the route explicitly delegates it.

What actually enables SSO

Three things together:

  • the same authentication provider verifies both routes;

  • a shared cookie domain (cookieDomain) covers every application host;

  • both routes are served by the same Gate One deployment.

Adding a second route alone does not create SSO. Replacing the provider alone does not create SSO either. The second application must use the same provider and share the same session cookie domain.

The complete sequence and configuration are in the multi-app SSO example.

Logout and revocation

The RP session lifetime is Gate One’s own (sessionTtlSeconds, one hour by default), independent of the identity provider’s short ID-token lifetime. Logout clears the cookie and records the revocation:

  • RP-initiated logout uses the provider’s end_session_endpoint;

  • back-channel logout is validated and persisted;

  • a revoked sid/sub is refused on the next request.

A revocation covers only sessions and tokens issued before it: a new sign-in after a logout is accepted — a user is never locked out by their own logout — while a copied cookie from before the logout still fails.

The revocation TTL defaults to the issuer’s advertised refresh-token lifetime, or 30 days. It is never shorter than the session TTL.

Register the logout redirect at the IdP

RP-initiated logout sends the originating application as post_logout_redirect_uri. Register every application host as a valid post-logout redirect URI:

  • Keycloak: client → Valid post logout redirect URIs, one https://app.example.com/* per application host;

  • the embedded IAM: tenants[.postLogoutRedirectUris] (empty falls back to redirectUris, the login host only).

If the IdP rejects that URI it shows an error and does not end its SSO session. Gate One’s own session is gone, but the next visit finds the IdP session and signs the user straight back in — so login looks "refused" even though no error is shown.

Troubleshooting

SymptomCause

Invalid redirect uri at logout

the application host is not a registered post-logout redirect URI

signed back in immediately after logout, or login "refused" without an error

the IdP SSO session was not ended because its post-logout redirect was rejected

"Login session expired" right after returning from the IdP

the sign-in took longer than the transaction window (15 minutes), or a second sign-in in the same browser replaced it

Operational notes

  • Same parent domain required. cookieDomain must cover every application host. app.company.com and app.other.com cannot share a cookie. For unrelated domains, use cross-domain SSO: each domain keeps its own cookie and the IdP session provides the single login.

  • Secrets never in the file. Use clientSecretEnv.

  • Several replicas? See Horizontal scaling for the shared-state requirement.

Important
  • Gate One does not create users, passwords or refresh tokens; that is the identity provider’s job (or the optional embedded IAM).

  • A route can bind only one authentication provider. Multi-provider hosting uses authProviders + auth.provider and one provider per route. Cross-TLD SSO uses ssoGroups + routes[].hosts so the shared provider settings are declared once.

  • Applications that need the raw access token must opt in; by default tokens are never forwarded.