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.

  1. Open Settings · Account → Members & roles → Single sign-on. Requires members.manage.
  2. Fill Issuer URL — the OIDC issuer from the table above. It must be an http(s) URL.
  3. Fill Provider name — the label your users see, default Company SSO.
  4. Fill Client id and Client secret for the confidential client you registered.
  5. 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.
  6. Choose Default role for new logins — start with viewer.
  7. Leave Groups claim as groups unless your identity provider names it differently.
  8. 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.
  9. Tick Auto-provision members on first login to create accounts and memberships automatically, and Enabled.
  10. 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.

  1. Create every custom role you will map. Requires members.manage.
  2. 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:

  1. Mint a write-scope API token on Alert intake & tokens (/portal/tokens) — see Integrations.
  2. Find your tenant id: GET /api/aiops/me returns one entry per membership with its tenant_id.
  3. PUT the whole provider, including the full map. Omitting client_secret keeps 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

  1. With the provider saved, click Test discovery. Requires members.manage. The button only appears once a provider exists.
  2. 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

Next steps