Contextator
ENTR

Administration & security

Single Sign-On

Federated sign-in over OIDC — turning it on, auto-provisioning, linking and unlinking your own account, and the guardrails that keep root a local-only account.

Updated:

Federated sign-in over OIDC, as a second door beside the password form — never a replacement for it.

Turning it on

Setting OIDC_ISSUER_URL is the on/off switch. Left empty, no discovery request is ever made and no button renders on /login, though the SSO routes stay registered (GET /api/auth/oidc/login answers 404, and the callback redirects to /login?oidc_error=not_configured). Set it, and discovery is fetched once and cached.

Variable Default Notes
OIDC_ISSUER_URL – The provider’s issuer URL. On/off switch for the whole feature
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET – Issued by the provider. OIDC_CLIENT_SECRET is a process secret like ADMIN_TOKEN — read from the environment, never written to the database, so no backup or dump ever carries it
OIDC_REDIRECT_URI – The callback URL registered with the provider, e.g. https://docs.example.com/api/auth/oidc/callback
OIDC_SCOPES openid profile email Space-separated scopes requested at the provider
OIDC_BUTTON_LABEL Single sign-on Text on the /login SSO button
OIDC_AUTO_PROVISION 0 1 lets a first successful provider sign-in create an account here on its own. Off by default: an unmapped provider identity is refused rather than silently handed an account
OIDC_DEFAULT_ROLE member Role a provisioned account gets. admin or member only — never root

There is nothing to configure from the dashboard for the provider itself; these variables are set by the operator in the instance’s environment. See Configuration for how settings are applied.

Signing in

A federated sign-in is always matched to an account by the provider’s sub claim, never its e-mail claim — an e-mail is exactly what a misconfigured or compromised provider could forge into reaching a different local account. Changing your e-mail at the provider does not disconnect you and cannot accidentally connect you to someone else’s account.

Whether a new account can be created this way at all is the operator’s choice (OIDC_AUTO_PROVISION), off by default. With it off, signing in through the provider is refused unless an admin already created the account or you have linked it yourself (below). Turn it on and a first successful sign-in mints an account with OIDC_DEFAULT_ROLE.

Once signed in, a federated account is governed by the same role table as any other account — nothing about what you can reach depends on how you signed in — and a provider outage never blocks local password sign-in. The two doors do not depend on each other.

Linking or unlinking your own account

Once signed in — by password or by the provider — every non-root account can connect or disconnect its own federated identity from its own account page, under Single sign-on. Connecting starts the identical provider redirect the login button uses, but links the identity it comes back with to the current session instead of signing in to whichever account already owns it. Linking a provider identity that is already linked to a different account is refused, not merged — each identity belongs to exactly one account.

Unlinking is self-service and revokes the account’s standing credentials in the same request: every session and every API token that account holds is invalidated the moment the identity is removed — including the session making the request — because unlinking is also what clears the way for a later promotion to root, and nothing opened while the account was still provably tied to an external identity provider should outlive that link. The same transaction revokes the account’s MCP OAuth credentials — every access and refresh token it was issued for /mcp/<project> — so an MCP client signed in as that account gets 401 on its next request and has to authorize again; other accounts’ credentials are untouched. The audit event of the unlink records how many were revoked, as detail.revokedMcpCredentials. Sign back in locally, since the link is gone, to get a working session again.

If the account has no local password and this link is its only way to sign in, unlinking is refused (409 last_sign_in_method) — nothing removed, nothing revoked — until an admin sets a password for it first with POST /api/users/:id/password.

root stays local, always

root cannot link a provider identity in the first place — the control never appears for it in the dashboard, and the API refuses the attempt directly (403 root_local_only). The reverse direction is guarded too: granting root to an account that still has a linked identity is refused (409 root_requires_unlink), on the Users page and at the API, checked ahead of the write — so the account’s role never actually becomes root while the link exists. As a second line of defence, a session’s role and sign-in method are re-read on every request; if an account somehow did reach root while still linked, a session opened over SSO for it would be signed out on its very next request rather than allowed to act as root. Only after unlinking can another root account grant the root role.

This is why the one account this product cannot recreate from a provider claim — root — never signs in over SSO.

The Admin API

Linking and unlinking are also two ordinary endpoints, callable from a script by a signed-in caller’s own session — see Admin API.

Arrow keys to move, Enter to open.