Guides
Enterprise SSO (OIDC & SAML)
Let your customer's workforce sign in to your project with their own corporate identity provider. Mudbase supports OpenID Connect (OIDC) and SAML 2.0, configured per project, with just-in-time (JIT) user provisioning so people land in your app as properly-scoped end users on their first login - no pre-import step.
Enterprise SSO requires a Growth plan or higher. OIDC and SAML connections are included on the Growth, Scale, and Enterprise plans. On Free, Basic, and Starter you cannot create or enable an SSO connection - upgrade to Growth or above first. The gate applies when you create or enable a connection; it never runs on the login hot path, so an already-enabled connection keeps working.
SSO connections are managed from Console → Settings → Single Sign-On. Everything the console does there is backed by the SSO admin API documented at the end of this page, so you can also script setup from your own backend or CI.
Who can configure SSO
The Single Sign-On settings tab is visible to project owners, admins, and developers (anyone with project-update permission). Viewers never see it. The same permission gates every SSO admin API call.
Concepts
| Term | What it is |
|---|---|
| Connection | One configured identity provider, scoped to a single project. A project can have more than one connection (for example, one OIDC and one SAML), up to a small per-project cap. |
| Protocol | oidc or saml. Chosen when you create the connection and fixed after creation - to switch, create a new connection. |
| Allowed domains | The email domains this connection serves (for example acme.com). A domain can be active on only one enabled connection across the whole platform, which is what keeps one tenant from intercepting another's users. |
| JIT provisioning | On a user's first successful SSO login, Mudbase creates their project end-user account automatically from the identity provider's claims. |
| Default role | The application role (customRole) assigned to JIT-provisioned users. Optional group-to-role mapping can override it (off by default). |
Every SSO user is created as a project end user - never an organization owner, admin, or platform admin. Identity-provider claims can influence a user's application role only; they can never grant console/team access or elevate the system role. This is enforced server-side and cannot be overridden by a claim.
Part 1 - OpenID Connect (OIDC)
Most enterprise identity providers (Entra ID, Okta, Google Workspace, Ping, Auth0, Keycloak) speak OIDC, so this is the path to reach for first.
Fixed URLs you register with your identity provider
These are the same for every OIDC connection on a project. You will paste the redirect/callback URL into your provider's app configuration:
Redirect / callback URL https://api.mudbase.dev/api/auth/sso/callback
Login start URL https://api.mudbase.dev/api/auth/sso/{projectId}/start
Domain discovery https://api.mudbase.dev/api/auth/sso/discover?email=user@acme.comRedirect / callback URL https://api.mudbase.dev/api/auth/sso/callback
Login start URL https://api.mudbase.dev/api/auth/sso/{projectId}/start
Domain discovery https://api.mudbase.dev/api/auth/sso/discover?email=user@acme.comThe redirect URL is fixed and global - it does not contain your project ID. Mudbase resolves the connection from the login flow it started, not from anything in the callback URL.
Step 1 - create the app at your identity provider
- In your identity provider, register a new OIDC / OpenID Connect web application.
- Set the redirect URI (also called sign-in redirect or callback URL) to the fixed callback above.
- Copy the Issuer URL, Client ID, and Client secret. The issuer is the base URL your provider serves
/.well-known/openid-configurationfrom (for examplehttps://login.acme.comorhttps://acme.okta.com).
Step 2 - create the connection in Mudbase
In Console → Settings → Single Sign-On, choose Add connection → OpenID Connect (OIDC) and fill in:
| Field | Notes |
|---|---|
| Display name | Shown on the sign-in button, for example "Acme Corp SSO". |
| Issuer URL | Mudbase fetches {issuer}/.well-known/openid-configuration to discover the authorization, token, JWKS, and userinfo endpoints automatically. |
| Client ID | From your provider. |
| Client secret | Write-only. Stored encrypted at rest and never returned by any endpoint. Leave blank when editing to keep the current secret. |
| Scopes | Defaults to openid email profile. |
| Allowed email domains | One per line. Only users whose verified email is on one of these domains can sign in through the connection. |
Step 3 - claim mapping and JIT provisioning
Claim mapping tells Mudbase which OIDC claim fills each profile field. The defaults match standard OIDC claims:
| Profile field | Default claim |
|---|---|
email | |
| First name | given_name |
| Last name | family_name |
| Avatar | picture |
- Just-in-time provisioning (on by default): the first time a user signs in, their end-user account is created from these claims and assigned the connection's default role.
- Group-to-role mapping is opt-in and off by default. When enabled, a claim (for example
groups) is matched against an explicit allowlist you define; any group not in the list falls back to the default role. A raw claim value is never used directly as a role, so an identity provider cannot invent a group namedownerand be granted owner access. Roles that require approval, payment, or KYC are never auto-granted through SSO.
Step 4 - token endpoint authentication (only if your provider needs it)
By default Mudbase sends the client credentials in the request body (client_secret_post). If your provider requires HTTP Basic authentication on the token endpoint, switch the connection to client_secret_basic. Most providers accept the default.
Step 5 - enable the connection
Turn Connection enabled on. Users whose email domain matches can now sign in. Point your app's "Sign in with SSO" button at the login start URL for the project, or call the discovery endpoint with the user's email to decide which button to show and where to send them.
What the OIDC login does under the hood
Mudbase runs a standard authorization-code flow with PKCE (S256), plus a session-bound state and nonce. It exchanges the code for an id_token, verifies that token against the provider's JWKS (signature, issuer, audience, expiry, and nonce), then issues your project's normal access and refresh tokens. The resulting session is identical in shape to any other Mudbase login, so the rest of your app needs no changes.
Part 2 - SAML 2.0
Use SAML when a customer's identity provider is SAML-only or their security team mandates it. The connection model, allowed-domains routing, JIT provisioning, default role, and group mapping all work the same as OIDC - only the trust and message details differ.
Step 1 - create the SAML connection in Mudbase first
Because SAML needs Mudbase's service-provider (SP) metadata before the identity provider can be configured, create the connection in Mudbase first (Add connection → SAML 2.0), give it a display name and allowed domains, and save it. Mudbase generates the SP signing keypair for you server-side and derives your SP details.
Step 2 - hand your SP details to the identity provider
Mudbase exposes these for the identity provider's "add service provider" step. The metadata document is the easiest path - most providers can import it from a URL:
SP metadata URL (import into your IdP) https://api.mudbase.dev/api/auth/saml/{projectId}/metadata
SP Entity ID https://api.mudbase.dev/api/auth/saml/{connectionId}/metadata
ACS / Reply URL (HTTP-POST binding) https://api.mudbase.dev/api/auth/saml/acs
Login start URL https://api.mudbase.dev/api/auth/saml/{projectId}/start
Single Logout (SLO) URL https://api.mudbase.dev/api/auth/saml/sloSP metadata URL (import into your IdP) https://api.mudbase.dev/api/auth/saml/{projectId}/metadata
SP Entity ID https://api.mudbase.dev/api/auth/saml/{connectionId}/metadata
ACS / Reply URL (HTTP-POST binding) https://api.mudbase.dev/api/auth/saml/acs
Login start URL https://api.mudbase.dev/api/auth/saml/{projectId}/start
Single Logout (SLO) URL https://api.mudbase.dev/api/auth/saml/sloThe SP metadata URL (keyed by project) is a document you fetch or import; the SP Entity ID (keyed by connection) is an identifier string. They look similar - do not swap them. Both the ACS URL and the SLO URL are fixed and server-controlled; Mudbase never derives them from an incoming message.
Step 3 - enter the identity provider's details in Mudbase
Back in the SAML connection form, fill in what the identity provider gives you:
| Field | Notes |
|---|---|
| IdP Entity ID (Issuer) | The provider's EntityID. It must match the <Issuer> in every assertion the provider sends. |
| IdP SSO URL | The provider's SingleSignOnService URL (HTTP-Redirect binding) - where Mudbase sends the login request. |
| IdP signing certificate(s) | Paste the PEM-encoded x509 signing certificate(s). Inbound assertion signatures are verified only against these pinned certificates, never a certificate embedded in the message. You can paste a second certificate to overlap during an identity-provider certificate rotation. |
| NameID format | Only stable formats are accepted: email address (emailAddress) or persistent. Transient NameIDs are rejected, because the subject identifier has to be durable. |
| Attribute mapping | Which SAML attribute name maps to each Mudbase field (email, first name, last name, groups). Leave the email attribute blank to use the NameID as the email. |
Step 4 - assertion policy and enable
- Signed assertions are always required. This cannot be turned off.
- Sign AuthnRequests is on by default; Mudbase signs outbound requests with the SP key it generated in step 1.
- IdP-initiated login ships OFF by default. Mudbase supports SP-initiated SAML only. For an identity-provider "app tile," configure it as a bookmark that points at the project's login start URL, which begins a normal SP-initiated flow. (A gated IdP-initiated accept-path exists but stays disabled unless it is explicitly enabled per environment and per connection.)
Turn Connection enabled on to go live.
SP signing-key rotation
Mudbase supports a staged rotation of the SP signing key without an outage: it can publish both the current and pending certificates in metadata during an overlap window, cut over to signing with the new key once your identity provider has re-imported the metadata, then retire the old key. This is driven from the SSO admin API (see below).
Domain verification and account linking
By default, if someone signs in through SSO with an email that already belongs to a local password (or social-login) account that was not created through this connection, the login is refused rather than silently linked. This is the primary defense against account takeover through a spoofed email claim.
To allow SSO to link into existing accounts on your domains, turn on Trust provider-verified email. That toggle only becomes available once every allowed domain has been verified by DNS. To verify a domain, publish the TXT record Mudbase shows you:
Record name _mudbase-sso-verify.acme.com
Record value mudbase-sso-verification={token}Record name _mudbase-sso-verify.acme.com
Record value mudbase-sso-verification={token}Then use Verify domain in the connection (or the verify-domain admin endpoint). Once all allowed domains are verified and the toggle is on, SSO will link to an existing account only when the provider also asserts the email is verified.
De-provisioning
There is no directory sync in this version. To cut off access, you can:
- Disable the connection - blocks new logins immediately.
- Revoke sessions for the connection - force-invalidates existing sessions (available in the connection and via the revoke-sessions admin endpoint).
- Rely on login-time re-evaluation - when group-to-role mapping is on, a user's application role is recomputed on each login, so a demotion at the identity provider takes effect on their next sign-in.
SSO admin API (for scripting and CI)
Everything the console does is available under /api/auth/sso. All admin routes require an owner/admin/developer token for the project.
| Method | Path | Description |
|---|---|---|
| GET | /api/auth/sso/projects/{projectId}/connections | List connections for a project. |
| POST | /api/auth/sso/projects/{projectId}/connections | Create a connection (protocol: "oidc" or "saml"). |
| GET | /api/auth/sso/projects/{projectId}/connections/{connectionId} | Get one connection (secrets are always stripped). |
| PATCH | /api/auth/sso/projects/{projectId}/connections/{connectionId} | Update fields, enable/disable, set trustIdpEmailVerified. |
| DELETE | /api/auth/sso/projects/{projectId}/connections/{connectionId} | Delete a connection (revokes its sessions). |
| POST | /api/auth/sso/projects/{projectId}/connections/{connectionId}/verify-domain | Run the DNS-TXT check for a domain. |
| POST | /api/auth/sso/projects/{projectId}/connections/{connectionId}/revoke-sessions | Force-revoke all sessions for the connection. |
SAML SP signing-key rotation is driven from .../connections/{connectionId}/saml/key-rotation (GET for status, then POST /start, /promote, /complete, or /cancel).
Example - create an OIDC connection:
POST /api/auth/sso/projects/{projectId}/connections
Authorization: Bearer {token}
Content-Type: application/json
{
"protocol": "oidc",
"displayName": "Acme Corp SSO",
"issuer": "https://acme.okta.com",
"clientId": "0oa...",
"clientSecret": "...",
"allowedDomains": ["acme.com"],
"defaultRole": "member",
"scopes": ["openid", "email", "profile"]
}POST /api/auth/sso/projects/{projectId}/connections
Authorization: Bearer {token}
Content-Type: application/json
{
"protocol": "oidc",
"displayName": "Acme Corp SSO",
"issuer": "https://acme.okta.com",
"clientId": "0oa...",
"clientSecret": "...",
"allowedDomains": ["acme.com"],
"defaultRole": "member",
"scopes": ["openid", "email", "profile"]
}The connection is created disabled; enable it with a PATCH once you have registered the redirect URL with your provider and confirmed the details.
Security notes
- Client secrets and SP private keys are encrypted at rest and never returned by any endpoint.
- OIDC uses PKCE (S256), a session-bound
state, and anonce;id_tokens are verified against the provider's JWKS (issuer, audience, expiry, nonce). - SAML requires signed assertions, pins trust to the certificates you supply, restricts NameID to stable formats, and rejects unsolicited assertions.
- Identity-provider claims and attributes can set a user's application role only. They can never grant organization ownership, admin, or platform-admin access.