new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Better Auth · Plugins · all subjects

oauth & social login

51 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

SSO plugin installation and setup

The SSO plugin is installed via `@better-auth/sso`. It is added to the betterAuth plugins array on the server side as `sso()` and to the client via `ssoClient()` from `@better-auth/sso/client`. The database must be migrated or schema generated after plugin installation to add necessary fields and tables.

SSO supports OIDC, OAuth2, and SAML 2.0

Single Sign-On (SSO) in Better Auth allows users to authenticate with multiple applications using a single set of credentials. The plugin supports OpenID Connect (OIDC), OAuth2 providers, and SAML 2.0.

OIDC provider registration via registerSSOProvider

To register an OIDC provider, use the `registerSSOProvider` endpoint. A redirect URL is automatically generated using the provider ID (e.g., if provider ID is 'hydra', redirect URL would be `{baseURL}/api/auth/sso/callback/hydra`). The endpoint path may vary depending on the base path configuration.

OIDC Discovery document fetching

Better Auth automatically fetches and validates the provider's OpenID Connect Discovery Document from `{issuer}/.well-known/openid-configuration`. This allows most endpoint-related fields in `oidcConfig` to be optional, as they are automatically hydrated from the Identity Provider's discovery document.

registerSSOProvider POST endpoint for OIDC (minimal config)

POST /sso/register (requires session). Minimal OIDC configuration with auto-discovery of endpoints. Parameters: providerId (string, unique identifier, must not collide with social providers or account linking providers), issuer (string, OIDC issuer URL where discovery document is fetched from), domain (string, bare email domain or comma-separated domains), oidcConfig (object with clientId and clientSecret required; other fields like authorizationEndpoint, tokenEndpoint, jwksEndpoint, discoveryEndpoint, scopes, pkce, and mapping are optional or auto-discovered).

Fields automatically discovered from OIDC discovery document

Better Auth automatically fills in the following fields from the IdP's discovery document if not explicitly provided: authorizationEndpoint, tokenEndpoint, jwksEndpoint, userInfoEndpoint, discoveryEndpoint, and tokenEndpointAuthentication (method for token endpoint client authentication). Relative paths in endpoint URLs are resolved relative to the issuer's base URL.

OIDC discovery error codes

OIDC discovery can fail with these structured error codes: issuer_mismatch (IdP's discovery document reports different issuer than configured), discovery_incomplete (required fields like authorization_endpoint, token_endpoint, jwks_uri missing), discovery_not_found (discovery document endpoint returned 404), discovery_timeout (IdP did not respond within timeout window, default 10 seconds), discovery_invalid_url (discovery URL is malformed or uses unsupported protocol), discovery_untrusted_origin (discovery URL or discovered URLs not trusted by app's trusted origins configuration), discovery_invalid_json (discovery response is empty or not valid JSON), unsupported_token_auth_method (IdP only supports token auth methods Better Auth doesn't support).

Supported OIDC token authentication methods

Better Auth supports these token endpoint authentication methods: client_secret_basic and client_secret_post. If an IdP advertises only unsupported methods (e.g., private_key_jwt, tls_client_auth, or 'none' for public clients), you can explicitly override the method using tokenEndpointAuthentication in oidcConfig.

Better Auth does not support implicit-only OIDC flows

Better Auth requires both token_endpoint and jwks_uri even though the OIDC spec allows implicit-only providers to omit token_endpoint. Registration will fail if these are missing.

SAML provider registration via registerSSOProvider

To register a SAML provider, use the `registerSSOProvider` endpoint with SAML configuration details. The provider will act as a Service Provider (SP) and integrate with your Identity Provider (IdP). Registration requires providerId, issuer, domain, and samlConfig with entryPoint, cert, callbackUrl, and other configuration.

SAML configuration parameters

SAML configuration includes: entryPoint (IdP SSO endpoint), cert (IdP certificate), callbackUrl (Assertion Consumer Service URL), audience (SP identifier), wantAssertionsSigned (boolean), signatureAlgorithm and digestAlgorithm (e.g., 'sha256'), identifierFormat (e.g., 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'), idpMetadata (with metadata XML, privateKey, privateKeyPass, isAssertionEncrypted, encPrivateKey, encPrivateKeyPass), spMetadata (with metadata XML, binding, privateKey, privateKeyPass, isAssertionEncrypted, encPrivateKey, encPrivateKeyPass), and mapping (id, email, name, firstName, lastName, emailVerified, extraFields).

IdP-initiated SAML SSO flow

Better Auth supports IdP-initiated SSO flows where users access the application directly from their Identity Provider dashboard (e.g., Okta, Azure AD, OneLogin). The IdP POSTs SAMLResponse to `/api/auth/sso/saml2/callback/{providerId}`, Better Auth processes the assertion and creates a session, then redirects to the application. No additional route handler is required as the callback route automatically handles both GET and POST requests.

IdP-initiated SAML callback URL configuration

For IdP-initiated SAML flows without a client-side callbackURL (since signIn.sso() is not used), configure `idpInitiatedCallbackUrl` either globally under the `saml` plugin options or per provider under `samlConfig`. The provider setting takes precedence. If neither is configured, the redirect falls back to the Better Auth base URL, which can result in a 404 in split-origin setups. Valid URLs are relative paths (e.g., '/dashboard') or URLs matching configured trustedOrigins; malicious or protocol-relative URLs are blocked.

Get Service Provider metadata endpoint

For SAML providers, retrieve the Service Provider metadata XML that needs to be configured in your Identity Provider using the `spMetadata` API endpoint. Example: `auth.api.spMetadata({ query: { providerId: 'saml-provider', format: 'xml' // or 'json' } })`. The response contains the metadata XML or JSON.

Sign in with SSO client methods

The client provides `authClient.signIn.sso()` method with these variations: sign in by email with domain matching via `email: 'user@example.com'`, sign in by domain via `domain: 'example.com'`, sign in by organization slug via `organizationSlug: 'example-org'`, sign in by provider ID via `providerId: 'example-provider-id'`. Optional parameters include callbackURL, errorCallbackURL, newUserCallbackURL, scopes, loginHint, and requestSignUp.

signInSSO POST endpoint parameters

POST /sign-in/sso. Parameters: email (optional, used to identify the issuer to sign in with), organizationSlug (optional, slug of organization to sign in with), providerId (optional, ID of provider to sign in with), domain (optional, domain of provider), callbackURL (required, URL to redirect to after login), errorCallbackURL (optional), newUserCallbackURL (optional, URL to redirect to if user is new), scopes (optional, array of scopes to request), loginHint (optional, login hint for identity provider), requestSignUp (optional boolean, explicitly request sign-up).

Login hint handling in SSO

If email is provided and loginHint is not specified, the email will be sent as the login_hint to OIDC providers automatically. SAML flows do not support login_hint.

User provisioning in SSO

When a user is authenticated through SSO, if the user does not exist, the user will be provisioned using the `provisionUser` function. By default, `provisionUser` only runs when a new user is registered. If you want to run it on every login (e.g., to sync upstream identity provider profile changes), set `provisionUserOnEveryLogin` to `true`. If organization provisioning is enabled and a provider is associated with an organization, the user will be added to the organization.

provisionUser callback parameters and example

The `provisionUser` function receives: user (user object from database), userInfo (user information from SSO provider including attributes, email, name), token (OAuth2 tokens for OIDC providers, may be undefined for SAML), provider (SSO provider configuration). Example that updates user profile with SSO data, creates user-specific resources, syncs with external systems, and logs the SSO sign-in: ```ts provisionUser: async ({ user, userInfo, token, provider }) => { await updateUserProfile(user.id, { department: userInfo.attributes?.department, jobTitle: userInfo.attributes?.jobTitle, manager: userInfo.attributes?.manager, lastSSOLogin: new Date(), }); await createUserWorkspace(user.id); await syncUserWithCRM(user.id, userInfo); await auditLog.create({ userId: user.id, action: 'sso_signin', provider: provider.providerId, metadata: { email: userInfo.email, ssoProvider: provider.issuer, }, }); } ```

Automatic account linking with domain verification

When a provider's domain is verified through domain verification, it is trusted for automatic account linking. This means if a user signs in with an SSO provider (OIDC or SAML) and an existing account with the same email exists, the accounts will be linked automatically as long as the user's email domain matches the provider's verified domain.

Enable domain verification on client and server

To enable domain verification, set it on both client and server. Client: `createAuthClient({ plugins: [ssoClient({ domainVerification: { enabled: true } })] })`. Server: `betterAuth({ plugins: [sso({ domainVerification: { enabled: true } })] })`. After enabling, migrate or generate the database schema.

Domain verification process steps

Domain verification follows these steps: (1) When an SSO provider is registered, a verification token is issued and returned in the response, (2) Add a TXT DNS record with host `_better-auth-token-{provider-id}` (underscore prepended, and tokenPrefix can be customized via domainVerification.tokenPrefix option) and value set to the verification token, (3) Wait for DNS propagation (up to 48 hours, usually faster), (4) Submit a validation request via the /sso/verify-domain endpoint.

verifyDomain POST endpoint

POST /sso/verify-domain (requires session). Parameter: providerId (string, the provider id to verify). This endpoint validates domain ownership via DNS TXT record verification. If verification is successful, the SSO provider domain is marked as verified. If the provider is updated or deleted while DNS verification is in progress, returns 409 response with SSO_PROVIDER_CHANGED code; reload the provider, confirm current domains, and retry verification.

Domain verification token expiry and renewal

Every domain verification token has a default expiry of 1 week from when it was issued or when the SSO provider was registered. After expiry, the token cannot be used. Use the requestDomainVerification endpoint to create a new verification token.

requestDomainVerification POST endpoint

POST /sso/request-domain-verification (requires session). Parameter: providerId (string, the provider id). Creates a new domain verification token when the previous token has expired.

Shared redirect URI for OIDC providers

By default, each OIDC provider gets its own callback URL (`/sso/callback/:providerId`). To configure all providers to share a single redirect URI, set `redirectURI` option in the sso plugin: `sso({ redirectURI: '/sso/callback' })` (relative path) or `sso({ redirectURI: 'https://login.example.com/callback' })` (full URL). The provider ID is stored in the OAuth state so the callback can identify which provider initiated the flow.

Shared redirect URI only affects OIDC providers

The redirectURI option only affects OIDC providers. SAML providers use a separate ACS endpoint that is configured automatically. Both the shared endpoint and per-provider endpoints are always registered for backward compatibility.

SAML endpoints automatically created by plugin

The SSO plugin automatically creates these SAML endpoints: SP Metadata endpoint at `/api/auth/sso/saml2/sp/metadata?providerId={providerId}`, and SAML Callback endpoint at `/api/auth/sso/saml2/callback/{providerId}` (supports both GET and POST).

Default SAML SSO Provider configuration

A default SAML provider can be configured in the sso plugin's defaultSSO option as an array containing provider configuration. This allows testing SAML authentication without setting up providers in the database. The defaultSSO provider supports all the same configuration options as regular SAML providers. It will be used when no matching provider is found in the database.

SAML Service Provider configuration fields

SAML Service Provider (SP) configuration includes: metadata (XML metadata for Service Provider), binding (binding method, typically 'post' or 'redirect'), privateKey (private key for signing AuthnRequests), privateKeyPass (password for the private key), isAssertionEncrypted (whether assertions should be encrypted), encPrivateKey (private key for decryption if encryption enabled), encPrivateKeyPass (password for encryption private key).

SAML signed AuthnRequests configuration

Some enterprise IdPs (Okta, Azure AD, ADFS) require signed AuthnRequests. Enable with: `samlConfig: { authnRequestsSigned: true, spMetadata: { privateKey: '---••••••--\n...' } }`. The SP metadata endpoint will automatically include `AuthnRequestsSigned="true"` when enabled.

SAML Identity Provider configuration fields

SAML Identity Provider (IdP) configuration includes: metadata (XML metadata from your Identity Provider), privateKey (private key for IdP communication, optional), privateKeyPass (password for IdP private key if encrypted), isAssertionEncrypted (whether assertions from IdP are encrypted), encPrivateKey (private key for IdP assertion decryption), encPrivateKeyPass (password for IdP decryption key).

SAML attribute mapping to user fields

SAML attribute mapping configuration: id (default 'nameID'), email (default 'email' or 'nameID'), name (default 'displayName'), firstName (default 'givenName'), lastName (default 'surname'). Also supports extraFields for custom attributes like department, role, or phone number.

ssoProvider table schema

The ssoProvider database table contains: id (string, primary key, database identifier), issuer (string, issuer identifier), domain (string, domain of provider), oidcConfig (string optional, OIDC configuration as JSON string), samlConfig (string optional, SAML configuration as JSON string), userId (string, foreign key to user.id), providerId (string, unique, provider ID used to identify provider and generate redirect URL), organizationId (string optional, organization ID if provider linked to organization).

ssoProvider table with domain verification schema

When domain verification is enabled, the ssoProvider schema is extended with: domainVerified (boolean optional, flag indicating whether provider domain has been verified).

SSO plugin options overview

SSO plugin server options include: provisionUser (custom function to provision user when they sign in via SSO provider), provisionUserOnEveryLogin (if true, provisionUser callback runs on every login not just registration, defaults to false), organizationProvisioning (options for provisioning users to organization), defaultOverrideUserInfo (override user info with provider info by default), disableImplicitSignUp (disable implicit sign up for new users), redirectURI (for shared OIDC callback URL), domainVerification (enable domain verification), saml (SAML-specific options), defaultSSO (array of default SAML provider configurations).

Provisioning best practice: idempotent operations

When provisionUserOnEveryLogin is enabled, ensure provisioning functions can be safely run multiple times. Check if already provisioned before creating resources, and always update attributes as they might change between logins. Example: check existingProfile.ssoProvisioned flag, create resources only if not provisioned, then mark as provisioned while always updating attributes from userInfo.

Provisioning best practice: error handling

Handle provisioning errors gracefully to avoid blocking user sign-in. Wrap external system calls in try-catch, log errors for debugging, but allow user authentication to succeed even if provisioning fails. This prevents IdP sync issues from preventing login.

Provisioning best practice: conditional logic

Only run certain provisioning steps when needed. For example, only process role assignment for certain providers using provider.providerId checks, or only sync attributes for specific domains. This improves performance and prevents unnecessary operations.

OIDC discovery relative endpoint resolution

Better Auth resolves relative endpoint paths in OIDC discovery relative to the issuer's base URL, preserving the path when available. Examples: issuer 'https://your-org.okta.com' with token_endpoint '/v1/tokens' normalizes to 'https://your-org.okta.com/v1/tokens'; issuer 'https://your-org.okta.com/v1' with token_endpoint '/tokens' normalizes to 'https://your-org.okta.com/v1/tokens'.

provisionUser callback in SSO plugin

The provisionUser option accepts a custom function that is called to provision a user when they sign in with an SSO provider.

provisionUserOnEveryLogin SSO option

The provisionUserOnEveryLogin option is a boolean that controls whether the provisionUser callback is called on every login, not just when a new user is registered. It defaults to false.

SSO organizationProvisioning options

The organizationProvisioning option in SSO plugin is an object with three properties: disabled (boolean, default false) to disable organization provisioning, defaultRole (string enum of 'member' or 'admin', default 'member') for the default role of new users, and getRole (function) for custom logic to determine the role for new users.

defaultOverrideUserInfo SSO option

The defaultOverrideUserInfo option is a boolean that controls whether to override user info with the provider info by default. It defaults to false.

disableImplicitSignUp SSO option

The disableImplicitSignUp option is a boolean that disables implicit sign up for new users. When set to true, sign-in needs to be called with requestSignUp as true to create new users. It defaults to false.

providersLimit SSO option

The providersLimit option configures the maximum number of SSO providers a user can register. It accepts a number or function, and defaults to 10. Set to 0 to disable SSO provider registration.

redirectURI SSO option for OIDC callbacks

The redirectURI option accepts a custom redirect URI for OIDC SSO callbacks. When set, all OIDC providers share this single callback URL instead of per-provider URLs, with the provider ID stored in the OAuth state. It can be a relative path (e.g., '/sso/callback') or a full URL.

SSO domainVerification configuration

The domainVerification option is an object with enabled (boolean) to enable or disable the feature, and tokenPrefix (string, default 'better-auth-token') which is the prefix used to generate the domain verification identifier with an underscore automatically prepended.

defaultSSO option for testing and development

The defaultSSO option accepts an array of default SSO providers for testing and development. Each object in the array contains: domain (string, required) for bare email domain(s) to match, providerId (string, required) for the provider ID to use, samlConfig (SAMLConfig, optional) for SAML configuration, and oidcConfig (OIDCConfig, optional) for OIDC configuration. These providers are used when no matching provider is found in the database.

SSO SAML security options

The saml option is an object containing SAML security settings: enableInResponseToValidation (boolean, default true) to enable InResponseTo validation for SP-initiated SAML flows, allowIdpInitiated (boolean, default true) to allow IdP-initiated SSO, requestTTL (number, default 300000 ms) for AuthnRequest record TTL, clockSkew (number, default 300000 ms) for timestamp validation tolerance, requireTimestamps (boolean, default false) to require timestamp conditions in SAML assertions, algorithms.onDeprecated (string enum of 'reject', 'warn', 'allow', default 'warn') for deprecated algorithm handling, maxResponseSize (number, default 262144 bytes) for maximum SAML response size, and maxMetadataSize (number, default 102400 bytes) for maximum IdP metadata XML size.

SSO plugin modelName and fields configuration

The SSO plugin allows customization of database schema through modelName (string, default 'ssoProvider') for the SSO provider table name, and fields object with customizable column names: issuer (default 'issuer'), oidcConfig (default 'oidcConfig'), samlConfig (default 'samlConfig'), userId (default 'userId'), providerId (default 'providerId'), organizationId (default 'organizationId'), and domain (default 'domain').

Give your agent this brain