SSO Setup
Operaide delegates authentication to an external OpenID Connect (OIDC) identity provider. Users sign in at the provider, and Operaide receives a signed identity token. The token drives session creation and auto-provisions an account on first sign-in.
Works with any spec-compliant OIDC provider: Microsoft Entra ID, Keycloak, Google Workspace, Okta, Auth0, and others. One provider per deployment. Email-and-password login stays available unless you disable it (see Disable email login).
Prerequisites
- Administrative access at your OIDC provider (to register an OAuth application).
AUTH_OPENID_*environment variables editable for the Operaide deployment (typically via the operator's.envfile).- The public URL Operaide is reachable at (
ROOT_URL).
Register Operaide at your identity provider
Register Operaide as an OAuth application at your provider with:
| Field | Value |
|---|---|
| Redirect URI | {ROOT_URL}/_oauth/openid |
| Grant type | Authorization Code with PKCE |
| Client authentication | Confidential client (client secret) |
After registration, note three values for the next step:
- Client ID
- Client secret
- Discovery URL (the provider's
openid-configurationendpoint)
Example: Microsoft Entra ID
- Azure portal, then Entra ID, then App registrations, then New registration.
- Name:
Operaide. Supported accounts: Single tenant (unless you need multi-tenant). - Redirect URI: type
Web, valuehttps://your-operaide.example.com/_oauth/openid. - After creation, copy the Application (client) ID and the Directory (tenant) ID.
- API permissions, then Add a permission, then Microsoft Graph, then Delegated permissions. Add
openid,profile,email.User.Readis added by Entra by default; leave it. - Certificates and secrets, then New client secret, then copy the value immediately. Entra shows secrets only once.
- Discovery URL:
https://login.microsoftonline.com/<tenantId>/v2.0/.well-known/openid-configuration.
Optional: if you plan to surface Entra group memberships on Operaide accounts, open Token configuration and add a groups claim.
Configure Operaide
Set these environment variables in the deployment's .env:
AUTH_OPENID_ENABLED=true
AUTH_OPENID_DISCOVERY_URL=<provider discovery URL>
AUTH_OPENID_CLIENT_ID=<client ID>
AUTH_OPENID_CLIENT_SECRET=<client secret>
Optional:
AUTH_OPENID_SCOPES=openid profile email # default
AUTH_OPENID_LOGIN_BUTTON_TEXT=SSO Login # default
AUTH_OPENID_GROUPS_CLAIM=groups # default; only set if your provider emits groups under a different key
AUTH_OPENID_PROVIDER_GUARANTEES_EMAIL_OWNERSHIP=false # default; set to true for Entra (see below)
Restart the container. The login page shows an SSO button with the configured text.
Trust setting for providers without email_verified
Operaide links a new SSO sign-in to a pre-existing local account by matching the email claim. That fallback is only used when the provider has verified the email address, either by emitting email_verified=true in the ID token or by the administrator attesting trust out-of-band. Without one of those two signals, Operaide refuses to link and only matches by the stable subject claim.
Provider emits email_verified=true? | AUTH_OPENID_PROVIDER_GUARANTEES_EMAIL_OWNERSHIP | Email-based linking |
|---|---|---|
| Yes | anything | Enabled |
| No (missing claim) | false (default) | Disabled |
| No (missing claim) | true | Enabled |
email_verified=false | anything | Disabled, login refused |
Set AUTH_OPENID_PROVIDER_GUARANTEES_EMAIL_OWNERSHIP=true only when the provider administratively guarantees that every user can only sign in with an address they actually own. Microsoft Entra is the typical case: Entra does not emit email_verified, but directory emails are administratively verified inside the tenant.
For providers with open or self-service signup that accept unverified email addresses, leave the default. Setting the flag to true there would let an attacker sign up at the provider with someone.else@your-company.com and take over the local account on first login.
Disable email login
For SSO-only or iframe-only deployments, disable the built-in email-and-password login so users cannot sign in any other way. Set:
NO_EMAIL_LOGIN=true
What changes:
| Surface | Effect |
|---|---|
| Login page | Email/password form is not rendered. SSO button stays visible. |
/register | Returns Not Found. |
/forgot-password, /reset-password | Return Not Found. |
/verify (email verification) | Returns Not Found. |
| Profile, then Security tab | Hidden. |
Server methods (loginUser, methodSubmitRegistration, Accounts.resetPassword) | Reject with 404. |
Default is false. The setting is independent of AUTH_OPENID_ENABLED: with NO_EMAIL_LOGIN=true and SSO disabled, the login page has no working sign-in path at all.
Do not combine NO_EMAIL_LOGIN=true with External Password Login. The HTTP Basic backend reuses the same email/password form; disabling the form blocks that flow as well.
First sign-in attaches to an organization
The first successful SSO sign-in for a given user creates the Operaide account and attaches it to an organization. Which organization depends on the emailDomainRegex setting.
See Auto-Provisioning for the shared rule, how to set the regex, deployment shapes, and what to do when a sign-in fails silently.
Troubleshooting
SSO redirect succeeds but no user account appears and the UI hangs on the login page.
No organization has an emailDomainRegex that matches the signing-in email. See Auto-Provisioning: When auto-provisioning fails silently.
AADSTS50011: The redirect URI specified in the request does not match the redirect URIs configured for the application. (Entra)
The redirect URI registered at the provider does not match {ROOT_URL}/_oauth/openid. Check that the value in the app registration matches exactly, including scheme (https://) and trailing segments.
Email claim not found in ID token (is the "email" scope requested?)
The ID token does not carry an email claim. Verify that AUTH_OPENID_SCOPES includes email, that the provider is configured to release the email claim, and that the account being used has an email address attached at the provider.
Sign-in redirects but the login page shows No pending credential found or a blank error.
Older Operaide builds masked server-side OIDC errors behind that message. Current builds surface the underlying cause on the login page and in the server log. If you still see the generic text, update to the latest patch release.
First SSO sign-in for a user that already exists locally fails or creates a duplicate.
The provider is not emitting email_verified=true and Operaide cannot link the SSO subject to the existing local account by email. Either set AUTH_OPENID_PROVIDER_GUARANTEES_EMAIL_OWNERSHIP=true (if the provider administratively verifies email ownership, for example Entra), or delete the pre-existing local account so the first SSO sign-in creates a fresh one.
Limitations
- One OIDC provider per deployment. Configuring a second provider in parallel is not supported. Users with multiple identity providers need separate Operaide deployments.
- No single logout (SLO). Signing out of Operaide does not sign the user out at the identity provider.
- No wildcard redirect URIs. The redirect URI is the exact
ROOT_URLfollowed by/_oauth/openid. - No per-organization provider. The OIDC configuration is deployment-scoped, not organization-scoped. All organizations on a deployment share the same provider.
- Group-to-role mapping is not automatic. The
groupsclaim is captured on the user record but does not drive Operaide roles today. Role assignment still happens through Organization Settings or the role API.
Common mistakes
- Redirect URI with trailing slash or wrong scheme.
{ROOT_URL}/_oauth/openidmust match exactly.http://vshttps://, trailing/, and extra path segments all fail. - Re-using the same app registration across Operaide instances. Each deployment needs its own registration because the redirect URI is deployment-specific.
- Assuming
groupsis standard OIDC. It is not. Only Entra and Keycloak commonly emit agroupsclaim; Auth0 uses a namespaced URL; some providers need explicit configuration. Verify what your provider emits before expecting groups on the account.
For regex and registration-flag pitfalls, see Auto-Provisioning: Common mistakes.