Appearance
Operator SSO, SCIM and access levels
Who this is for: Platform operators and security owners
What you'll achieve: Sign different admins into /operator with SSO or a break-glass account, provision them from your directory, and keep a full audit trail
Everything on this page is configured in the console at Operator → Configuration. Environment variables are only needed to bootstrap a brand new deployment.
Ways to sign in
| Method | Second factor | Use |
|---|---|---|
| OIDC SSO | Handled by your IdP. Optional TOTP per operator | Everyday access for named humans, with roles from groups or assigned per person |
| Email and password | TOTP always required | Break-glass when SSO is unavailable |
| Named API token | None (machine credential) | CLI, automation, scripts |
Bootstrap token (OPERATOR_API_TOKEN) | None | First-run setup only. Stops working once named access exists |
Local bypass (OPERATOR_AUTH_DISABLED=1) | None | Local and CI only. Ignored when NODE_ENV=production |
With none of these available, /operator fails closed. It never falls open.
First-run setup
- Set
OPERATOR_API_TOKENon the host and sign in at/operator/loginwith Use bootstrap token. - Give named humans a way in: either turn on SSO under Configuration → SSO, or go to Configuration → Admins and invite yourself as a
platform_adminand follow the emailed link to set a password and enrol an authenticator. - Go to Configuration → API tokens and create a named token for automation.
- Once named human access and a named token both exist, the bootstrap token stops being accepted. Remove it from the host.
If you need it back during an emergency, set OPERATOR_BOOTSTRAP_OVERRIDE=1. Every use is audited and emails your security address.
Configure SSO
- Register an OIDC app in Entra, Okta, or Google.
- Copy the redirect URI shown on Configuration → SSO into your IdP app. It is
{APP_URL}/api/operator/auth/oidc/callback. - Enter the issuer, client ID, and client secret. The secret is encrypted at rest with
INTEGRATION_ENCRYPTION_KEYand never returned to the browser. - Optionally restrict sign-in to specific email domains.
- Optionally map IdP groups to roles. Skip this if you would rather grant roles per person: see How roles are decided. Where someone matches several mapped groups, the highest role wins.
- Choose what happens for a first-time sign-in that matches no mapped group. Deny sign-in is the recommended default, and is safe even with no group mapping at all, because anyone you have already added keeps the role you gave them.
- Tick SSO is active and save.
Deployments already using the legacy OPERATOR_OIDC_* variables have them imported into this form once, automatically. After that the console is the only source of truth, so you can remove those secrets from the host.
You cannot switch SSO off if that would leave the shared bootstrap token as the only way in. Invite at least one admin with a password first, so you keep a break-glass account.
How roles are decided
Group mapping is optional. There are two ways to run this, and you can mix them.
Assign roles per person (simplest). Leave group mapping empty. On Configuration → Admins, add someone, pick their role, and choose Single sign-on as the sign-in method. They sign in with your identity provider and land on exactly that role. No password is created and MFA stays with your IdP. Because the account already exists, the default role can stay on Deny sign-in, so nobody who has not been added gets in.
Let the directory decide. Map at least one IdP group, or one SCIM group, to a role. Roles then follow group membership for everyone whose role you have not set by hand.
When a sign-in happens, the role is taken from the first of these that applies:
- A role you set on the Admins tab, marked Set here. Neither SSO nor SCIM overrides it.
- A local password account or a SCIM-provisioned record, for the same reason.
- The role the directory maps for that sign-in.
- Otherwise the role already on the account. A sign-in that maps nothing never silently relabels anyone.
An identity nobody has added, that the directory does not map either, is refused.
To hand a role back to the directory after setting it by hand, use Use directory next to that person. Their role is recalculated from group membership straight away and their sessions are revoked.
Directory provisioning (SCIM)
Configuration → SCIM gives you a SCIM 2.0 endpoint and bearer token for Entra, Okta, or Google.
- Endpoint:
{APP_URL}/api/operator/scim/v2 - Supported resources:
UsersandGroups, including PATCH
Two rules keep provisioning safe:
- Roles are never taken from the directory payload. New users arrive as
readonly. Groups arrive with no role at all, and you choose what each one grants on the SCIM tab, or assign roles per person instead. - While any SCIM token is active, SSO only authenticates. It will not create accounts, so someone removed from your directory cannot sign back in and re-provision themselves.
Deprovisioning disables the account and revokes its sessions immediately, but keeps the record so the audit trail survives. SCIM refuses to deprovision the last active platform admin.
Once at least one group grants a role, group membership becomes authoritative for directory-managed operators. Removing someone from a mapped group lowers their role straight away, and losing every mapped group leaves them readonly. If that removes your last platform admin, the change still applies (stale privilege is the worse outcome) and your security address is emailed so you can restore access.
While no group grants a role, membership changes nothing at all, so syncing groups you have not mapped is harmless.
Local break-glass accounts and any operator whose role an admin set by hand are protected: SCIM can update their name and link their directory ID, but not change their role or take over their password.
Break-glass access
Invited operators set their own password and must enrol an authenticator app before they reach the console. Nobody, including you, can sign in with a password alone.
- Passwords are at least 12 characters, hashed with bcrypt
- Five failed attempts locks the account for 15 minutes
- Ten backup codes are issued at enrolment, each usable once
- Invite and reset links expire after 48 hours and work once
Reset someone's MFA or password from Configuration → Admins. Both revoke their existing sessions. A password reset keeps their existing authenticator: only an explicit MFA reset clears it and issues new backup codes.
MFA for SSO operators
SSO operators inherit whatever your identity provider enforces, so they are not challenged again by default. To require a SchoolRota authenticator as well, tick Require next to that person on the Admins tab. They will enrol on their next sign-in.
Roles
| Role | Provision | Flags / billing | Impersonate | Inbox | Audit log | Configuration |
|---|---|---|---|---|---|---|
platform_admin | Yes | Yes | Yes | Read and reply | Yes | Yes |
support | No | No | Yes | Read and reply | Yes | No |
readonly | No | No (view only) | No | Read only | Yes | No |
Named API tokens carry a role of their own and can be narrowed further to specific permissions, so automation does not have to run as an admin. The bootstrap token always acts as platform_admin.
Step-up re-authentication
Changing access settings and starting an impersonation session both need fresh proof of identity, even inside a live session. You are prompted inline and the action then continues on its own.
If you have an authenticator, you confirm with a code. If you sign in with SSO and have never set one up, you are sent back to your identity provider to sign in again instead, then returned to the page you were on. Either way the confirmation lasts 15 minutes. Machine tokens cannot perform these actions at all.
Sessions
Sessions last 8 hours, or 30 minutes idle. Configuration → Sessions lists every active session with its sign-in method, IP, and last activity, and lets you revoke any of them. Changing someone's role, status, password, or MFA revokes their sessions automatically.
Audit log
Every sign-in (including denied ones), logout, lockout, password set, MFA change, SSO and SCIM configuration change, token creation, provisioning action, flag change, and impersonation is written to audit_events with the acting operator. Browse at /operator/audit, filter to Access and sign-in only for a security review, and use Export CSV to take it away.
Optional network fence
Set OPERATOR_IP_ALLOWLIST to a comma-separated list of IPs or prefixes (for example 203.0.113.4,198.51.100.) to serve 404 for /operator and its API from anywhere else. The SCIM endpoint is exempt, since your identity provider calls it from its own addresses.
Redis (related platform note)
Optional REDIS_URL shares rate limits across machines and powers the BullMQ worker. Operator and tenant sessions stay in the database and cookies, not Redis. See Deployment.

