IdP-initiated SAML SSO workflow
In IdP-initiated SSO: (1) User clicks app icon in IdP dashboard, (2) IdP POSTs SAMLResponse to /api/auth/sso/saml2/sp/acs/{providerId}, (3) Better Auth processes the assertion, creates a session, and redirects to the application, (4) Browser follows the redirect with a GET request automatically.
POST /sso/verify-domain endpoint
The POST /sso/verify-domain endpoint verifies domain ownership for an SSO provider. It requires a session. It accepts a providerId parameter (string) that identifies the provider, for example 'acme-corp'.
Domain verification token expiry
Every domain verification token has a default expiry of 1 week from the moment it was issued or when the SSO provider was registered. After expiry, the token cannot be used.
POST /sso/request-domain-verification endpoint
The POST /sso/request-domain-verification endpoint creates a new domain verification token. It requires a session. It accepts a providerId parameter (string) that identifies the provider, for example 'acme-corp'.
SAML SP Metadata endpoint
The SAML SP Metadata endpoint is located at /api/auth/sso/saml2/sp/metadata?providerId={providerId} and is automatically created by the plugin.
SAML ACS endpoint
The SAML Assertion Consumer Service (ACS) endpoint is located at /api/auth/sso/saml2/sp/acs/{providerId} and is automatically created by the plugin. It supports both GET and POST requests and handles both SP-initiated and IdP-initiated SSO flows.
SAML SP-initiated flow
In an SP-initiated SAML SSO flow, the user clicks 'Sign in with SSO' in the application, which redirects to the IdP. The IdP then POSTs the SAMLResponse to the ACS callback endpoint.
SAML IdP-initiated flow
In an IdP-initiated SAML SSO flow, the user clicks the app icon in the IdP dashboard (such as Okta or Azure AD), and the IdP POSTs the SAMLResponse directly to the ACS callback endpoint.
SAML ACS URL automatic derivation
Better Auth derives the ACS URL automatically from the baseURL and providerId, so no SP-side configuration is required.
SAML AudienceRestriction and entity ID validation
The IdP must include an AudienceRestriction for the SP. The accepted audience is the SP entity ID, or the explicit audience value in samlConfig when you need to match an IdP-specific SP identifier. Better Auth also validates bearer Recipient and response Destination values against the provider's ACS endpoints.
SAML post-login redirect via callbackURL parameter
The post-login redirect destination for SAML SSO is controlled by the callbackURL parameter passed to the client-side signIn.sso() call. Example: await authClient.signIn.sso({ providerId: 'my-provider', callbackURL: '/dashboard' });
IdP-initiated SAML flow idpInitiatedCallbackUrl configuration
For unsolicited IdP-initiated flows where signIn.sso() is not used and no client-side callbackURL is set, configure idpInitiatedCallbackUrl in the provider's samlConfig or in the global saml plugin options. The provider setting takes precedence over the global setting. If neither is configured, the existing redirect behavior is preserved. When updating a provider, pass null for samlConfig.idpInitiatedCallbackUrl to remove its override and fall back to the global setting.
SAML callback route GET and POST support
The callback route for SAML (/api/auth/sso/saml2/sp/acs/{providerId}) supports both GET and POST methods automatically. No additional route handlers need to be created in your framework.
ssoProvider table additionalFields schema configuration
You can add custom columns to the ssoProvider table using schema.ssoProvider.additionalFields. This allows storing provider metadata such as a display name. Example: additionalFields: { displayName: { type: 'string', required: true } }
ssoProvider table schema fields
The ssoProvider table includes these fields: id (string, primary key), issuer (string), domain (string), oidcConfig (string, optional, JSON), samlConfig (string, optional, JSON), userId (string, foreign key to user.id), providerId (string, unique), organizationId (string, optional). When domain verification is enabled, an additional domainVerified field (boolean, optional) is added.
IdP-initiated SAML flow redirect behavior in split-origin setups
IdP-initiated flows do not carry a Better Auth-generated RelayState with a client-side callback URL. The redirect falls back to the Better Auth base URL. In split-origin setups (frontend on different origin from auth server), this can result in a 404 error. Configure idpInitiatedCallbackUrl globally or per provider to return successful sign-ins and validation errors to the frontend.
SAML redirect URL security validation
Better Auth validates all redirect URLs to prevent open redirect attacks. Only relative paths (e.g., /dashboard) and URLs matching configured trustedOrigins are allowed. Malicious URLs like https://evil.com or protocol-relative URLs (//evil.com) are automatically blocked.
provisionUser option
provisionUser is a custom function to provision a user when they sign in with an SSO provider. Type: function.
provisionUserOnEveryLogin option
provisionUserOnEveryLogin is a boolean option (default: false). When true, the provisionUser callback runs on every login, not just on registration.
organizationProvisioning option
organizationProvisioning is an object option for provisioning users to an organization. It has two sub-options: disabled (boolean, default: false) to disable organization provisioning, and defaultRole (string, enum: 'member' or 'admin', default: 'member') to set the default role for new users. It also accepts getRole as a custom function to determine the role for new users.
defaultOverrideUserInfo option
defaultOverrideUserInfo is a boolean option (default: false). When true, user info is overridden with the provider info by default.
disableImplicitSignUp option
disableImplicitSignUp is a boolean option (default: false). When true, implicit sign up for new users is disabled. When enabled, sign-in needs to be called with requestSignUp as true to create new users.
providersLimit option
providersLimit is a number or function option (default: 10) that configures the maximum number of SSO providers a user can register. Set to 0 to disable SSO provider registration.
redirectURI option for OIDC SSO
redirectURI is a string option (not required) for custom redirect URI in OIDC SSO callbacks. When set, all OIDC providers share this single callback URL instead of per-provider URLs. The provider ID is stored in the OAuth state. Can be a relative path (e.g., '/sso/callback') or a full URL.
domainVerification option configuration
domainVerification is an object option to configure domain verification. It has two properties: enabled (boolean, not required) to enable or disable domain verification, and tokenPrefix (string, not required, default: 'better-auth-token') used to generate the domain verification identifier with an underscore automatically prepended.
defaultSSO option for testing and development
defaultSSO is an array option to configure default SSO providers for testing and development. These providers are used when no matching provider is found in the database. Each item has domain (string, required) for bare email domain or comma-separated domains, providerId (string, required), samlConfig (SAMLConfig, optional), and oidcConfig (OIDCConfig, optional).
SAML security options configuration
The saml option is an object for SAML security with sub-options: enableInResponseToValidation (boolean, default: true) for SP-initiated SAML flows, allowIdpInitiated (boolean, default: true) to allow IdP-initiated SSO, requestTTL (number, default: 300000 ms) for AuthnRequest records, clockSkew (number, default: 300000 ms) for timestamp validation tolerance, requireTimestamps (boolean, default: false) to require timestamp conditions in assertions, algorithms.onDeprecated (string enum: 'reject'|'warn'|'allow', default: 'warn') for deprecated algorithms, maxResponseSize (number, default: 262144 bytes) for SAML response size, and maxMetadataSize (number, default: 102400 bytes) for metadata size.
modelName option
modelName is a string option (default: 'ssoProvider') specifying the model name for the SSO provider table.
fields option for custom column names
The fields option allows customizing column names in the ssoProvider table: issuer (default: 'issuer'), oidcConfig (default: 'oidcConfig'), samlConfig (default: 'samlConfig'), userId (default: 'userId'), providerId (default: 'providerId'), organizationId (default: 'organizationId'), and domain (default: 'domain').