Single sign-on
Register this platform at your identity provider, connect it, map groups to roles, test discovery, what login looks like afterwards, and why SSO can never mint a tenant admin.
How-to · Updated 2026-10-17 · Describes release 0.1.164
The Single sign-on card on Settings · Account → Members & roles connects one OIDC identity provider to your workspace, so your users sign in with their work email and never hold a password on this platform. This page is the whole procedure, provider side and platform side. Inviting people by link instead is on Members and roles; the roles a group can map to are in the Permissions reference.
Per-tenant SSO
One OIDC issuer per tenant. Your users then sign in with their work email and never hold a password on this platform.
First, register this platform at your provider
SSO is an exchange: you paste your provider's details here, and your provider has to be told about this platform. Doing only the first half is the usual first failure — the sign-in gets as far as your provider and stops with redirect_uri did not match.
At your identity provider, create an OIDC confidential client (not SAML — this platform speaks OIDC only) and register these two URLs on it. Both are shown with copy buttons at the top of the Single sign-on card, filled in with this deployment's real address:
| What to register | Value | Notes |
|---|---|---|
| Redirect URI / callback URL | https://<your-deployment>/oidc/callback |
Required. Must match exactly, https included, no trailing slash added. |
| Post-logout redirect URI | https://<your-deployment>/login |
Optional. Without it, signing out here leaves your provider's session alive. |
The same callback serves every workspace on the deployment — tenants are told apart by their issuer, not by a per-tenant URL. Each vendor labels the field differently: Entra ID calls it a Redirect URI under platform type Web, Okta a Sign-in redirect URI, Keycloak a Valid redirect URI, Auth0 an Allowed Callback URL.
Then copy the client id and secret it gives you, and the issuer:
| Provider | Issuer URL |
|---|---|
| Microsoft Entra ID | https://login.microsoftonline.com/<tenant-guid>/v2.0 |
| Okta | https://<org>.okta.com/oauth2/default |
| Google Workspace | https://accounts.google.com |
| Auth0 | https://<tenant>.auth0.com/ |
| Keycloak | https://<host>/realms/<realm> |
Paste the issuer itself, never its discovery document — drop any trailing /.well-known/openid-configuration. Test discovery on the card fetches that document for you and reports what it found.
Entra ID needs one more thing: tick Trust email from this provider. It does not send email_verified, and without that box its logins are rejected as unverified.
Connect an identity provider
Create any custom roles you intend to map before saving the provider — the save validates that every role it references already exists in this tenant.
- Open Settings · Account → Members & roles → Single sign-on. Requires
members.manage. - Fill Issuer URL — the OIDC issuer from the table above. It must be an
http(s)URL. - Fill Provider name — the label your users see, default
Company SSO. - Fill Client id and Client secret for the confidential client you registered.
- Fill Email domains (comma-separated), for example
example.com. At least one is required, each must look like a real domain, and a domain belongs to exactly one identity provider platform-wide. - Choose Default role for new logins — start with
viewer. - Leave Groups claim as
groupsunless your identity provider names it differently. - Fill Group → role map (one per line: group = role), for example
sre-team = operator. See Map identity-provider groups to roles for the caveat on more than one mapping. - Tick Auto-provision members on first login to create accounts and memberships automatically, and Enabled.
- Click Save identity provider.
The card header grows an enabled status badge and a secret stored badge, the notice reads Identity provider saved., and a Test discovery button and a Remove button appear. The save is audited as idp.updated with the issuer and domain list.
Field notes: the client secret is write-only. Once stored, the label reads (stored — blank keeps it); leaving it blank keeps the current value, typing a value rotates it, and it is never rendered back to the browser. Where that secret physically lives and how it is encrypted is Security and data → The tenant secret store.
Map identity-provider groups to roles
The Group → role map takes one group = role per line. Save reports the exact line when a mapping is malformed, duplicated or names an unavailable SSO role; it never silently drops that line. Default-role choices and mappings exclude roles carrying members.manage; the server remains authoritative.
- Create every custom role you will map. Requires
members.manage. - Type the mappings, one per line, and save.
A group that maps to no role falls back to Default role for new logins. One mapping can never grant members.manage, no matter which role it names — see the note below.
To script it instead:
- Mint a write-scope API token on Alert intake & tokens (
/portal/tokens) — see Integrations. - Find your tenant id:
GET /api/aiops/mereturns one entry per membership with itstenant_id. PUTthe whole provider, including the full map. Omittingclient_secretkeeps the stored one.
curl -s -X PUT -H "Authorization: Bearer $AIOPS_TOKEN" \
-H "Content-Type: application/json" \
"https://aiops.example.com/api/aiops/$TENANT_ID/idp" \
-d '{"issuer":"https://login.example.com/realms/example",
"client_id":"aiops",
"provider_name":"Company SSO",
"email_domains":["example.com"],
"default_role":"viewer",
"groups_claim":"groups",
"group_role_map":{"sre-team":"operator","finance":"executive"},
"auto_provision":true,"enabled":true}'
The response echoes the stored provider with the full group_role_map and has_secret: true, and the change lands as another idp.updated row. Re-open the Single sign-on card and confirm before relying on it: if the map is right in the response but the field looks collapsed, do not press Save identity provider again.
Test discovery
- With the provider saved, click Test discovery. Requires
members.manage. The button only appears once a provider exists. - Read the notice under the form.
A working issuer returns Discovery OK — <authorization endpoint>. A broken one returns the error text; the button never fails with a server error. The probe fetches <issuer>/.well-known/openid-configuration through the same SSRF guard as datasource probes, so an issuer on a private address is reported as rejected rather than silently attempted.
What login looks like afterwards
The sign-in page grows a Company SSO — enter your work email box as soon as any enabled tenant provider exists, anywhere on the deployment. A user types their address and clicks Continue; the platform matches the email domain to your provider and redirects straight into it. A domain nobody claims returns No company SSO is configured for this email domain.
On return, the member is created with the role from the first matching group in Group → role map (group names are evaluated in sorted order for determinism), otherwise Default role for new logins. Existing members are never re-roled by a login — a role you assigned by hand always wins.
Your provider must assert email_verified for the address. Unlike the platform's own issuer, a tenant provider has no relax toggle: an unverified email is refused with sso email not verified, and a provider may only assert addresses inside the domains it claims (sso email domain not allowed for this provider).
Signing out asks your identity provider to end its session too (RP-initiated logout), so the next login is a real login. If your provider publishes no end_session_endpoint, or discovery fails, the platform falls back to ending the local session only.
Removing the provider with Remove identity provider stops SSO logins for those domains immediately; existing accounts and memberships survive. The removal is audited as idp.removed.
SSO can never mint a tenant admin
A role reachable through SSO can never carry members.manage. This is enforced three times: when the identity provider is saved, when a role referenced by it is created or edited, and again at login as a backstop. Saving a provider that points at such a role returns role '<name>' carries members.manage — not assignable via SSO; going the other way — adding members.manage to a role the provider already references — returns role '<name>' is assigned via SSO — it cannot carry members.manage. Tenant administration is always granted by a human already inside the tenant, never by a directory group.
Two related refusals: platform-staff email domains are reserved and cannot be claimed, and a customer-controlled provider can never auto-link onto a superadmin account, a local-password account, or an account already belonging to another tenant (account exists — ask a tenant owner to invite you). An account minted by any login method other than OIDC is refused as well.
Hosted-realm provisioning — the platform creating a dedicated Keycloak realm for you — is a platform-staff action, not something this card can do. Ask your account contact; the procedure is Customers and workspaces → Provision a Keycloak realm in the platform console handbook. It lands here as an idp.provisioned audit row.
Troubleshooting
Cross-cutting symptoms — a queued investigation, a missing page, an empty approval queue — are in Troubleshooting. The table below covers only the errors the Single sign-on card and an SSO login produce.
| Symptom | Cause | Fix |
|---|---|---|
role '<name>' carries members.manage — not assignable via SSO |
Saving an identity provider that maps to an admin role | Map the group to a role without members.manage and grant admin by hand |
role '<name>' is assigned via SSO — it cannot carry members.manage |
Adding members.manage to a role the provider already references |
Remove it from the provider's default role / group map first, or use a different role |
issuer must be an http(s) URL / client_id required |
Required identity-provider fields malformed or blank | Paste the issuer exactly as your provider publishes it, without a trailing path typo |
at least one email domain required / invalid email domain '<d>' |
Domain list empty or not a domain | Comma-separate bare domains, for example example.com, example.net |
email domain '<d>' is already claimed by another identity provider |
Domains are globally unique | Use a domain only your organisation owns, or contact your account contact |
email domain '<d>' is reserved for platform staff |
Staff domains cannot be claimed | Remove that domain from the list |
Test discovery returns an error instead of Discovery OK |
Issuer unreachable, wrong URL, or blocked by the SSRF guard | Verify the issuer serves /.well-known/openid-configuration from a reachable address |
sso email not verified |
Your provider did not assert email_verified |
Enable verified-email claims; tenant providers have no relax toggle |
sso email domain not allowed for this provider |
The asserted address is outside the claimed domains | Add the domain to Email domains, or fix the account's address |
account not provisioned on first SSO login |
Auto-provision members on first login is off | Tick it, or add the member by email first |
account exists — ask a tenant owner to invite you |
The address matches a staff, password or other-tenant account | Add that person as a member by email instead of relying on auto-link |
| SSO login lands with the wrong role | A membership already existed, or no group matched | Manual assignment always wins — change the role on the Members card |
| Users stopped being able to sign in with SSO | The provider was removed or Enabled was unticked | Re-save it; local accounts are unaffected |
Limits and gotchas
- One identity provider per tenant, and one owner of each email domain platform-wide.
- Keycloak realm provisioning is platform-staff only. The Single sign-on card connects a provider you already run; a hosted realm is arranged through your account contact.