SAML single sign-on for your app (Okta, Entra ID, Google Workspace)
Let your business customers' staff sign in to your app with their company identity provider over SAML 2.0: one connection per IdP, bound to the email domains it may sign in.
When you sell your app to companies, their IT team will ask for single sign-on. Add a SAML connection for each customer's identity provider and name the email domains it signs in. A user who types ada@acme.com goes to Acme's Okta, signs in there, and comes back to your app with a normal Sovaria session (MFA rules, session limits and your blocking hooks still apply).
#Add a connection
- Console › Authentication › SAML SSO › Add connection: a name (“Acme (Okta)”), the email domains (
acme.com), and the IdP's metadata XML (or its entity ID, sign-in URL and signing certificate). - Give the customer's IdP admin the ACS URL and Entity ID shown for the connection. Name ID format: email address. Sign the response or the assertion (unsigned or encrypted assertions are refused).
- Okta: Applications › Create App Integration › SAML 2.0: “Single sign-on URL” = ACS URL, “Audience URI” = Entity ID. Entra ID: Enterprise application › Single sign-on › SAML: Identifier = Entity ID, Reply URL = ACS URL. Google Workspace: Apps › Web and mobile apps › Add custom SAML app.
// Sign-in screen: "Continue with SSO"
await sov.auth.signInWithSSO({ email: 'ada@acme.com', redirectTo: 'https://app.example.com/auth/callback' })
// On /auth/callback
await sov.auth.handleEmailLink(window.location.href) // or exchangeCodeForSession(code)#Users
The first sign-in creates the app user (email verified, no password; your before-create hook runs and can refuse it). If an app user with that email already exists, the SAML identity is linked to it. Pair it with SCIM provisioning (Okta, Entra ID, Google Workspace) so leavers are switched off the moment the company deactivates them.
#Security
- The response must be signed with the connection's certificate and match the IdP's issuer, our audience and ACS URL, the time window and the sign-in request we sent (InResponseTo). Each assertion works once.
- Only addresses on the connection's domains are signed in, and a domain belongs to one connection per project, so one customer's IdP can't sign in or take over another domain's users.
- Metadata is parsed without entities or network access; certificates are stored encrypted and never returned.
- Only the project's owners and admins can add, change or remove connections.
#Errors back to your app
error on the redirect | Meaning |
|---|---|
saml_invalid | The response failed verification (signature, audience, time, request). Check the certificate and URLs in the IdP. |
saml_replayed | The same assertion was posted twice. |
domain_not_allowed | The signed-in email isn't on the connection's domains. |
signup_refused | Your before-create hook refused the new user. |
plan_required | The organization's plan doesn't include SSO. |
#Your own team (console SSO)
Separately, an organization on Team or Enterprise can make its members sign in to the Sovaria console with SAML: Organization › Settings › Enterprise SAML SSO (paste the IdP metadata or the three fields). That is for your team, not your app's users.
#Plans
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Enterprise SSO (SAML/OIDC) | — | — | — | ✓ | ✓ |
#Coming from Firebase or Supabase?
| Platform | What this is called there |
|---|---|
| Firebase | SAML via Identity Platform (paid upgrade) |
| Supabase | SAML 2.0 on Pro and above (CLI-configured) |
| Sovaria | SAML single sign-on for your app (Okta, Entra ID, Google Workspace) |
Moving an existing app? Migrate from Supabase or Firebase imports users (with their passwords), data, files and rules.