Organizations

Single sign-on

Organizations sign their members in through their own identity provider, with OIDC or SAML 2.0.
An organization's SSO tab: an OIDC provider with its redirect URI, and the DNS record that verifies its domain

Better Auth's SSO plugin. Each organization registers its own identity provider (Okta, Microsoft Entra ID, Google Workspace, …), and its members sign in through it with their work email.

Turning it on

Install the plugin's package

Terminal
pnpm add @better-auth/sso

Enable it

nuxt.config.ts
export default defineNuxtConfig({
  betterAuthUi: {
    organization: { enabled: true },
    sso: {
      enabled: true,
      // New providers work once a DNS record proves the organization owns their domains.
      domainVerification: true
    }
  }
})

Trust your identity providers' origins

Better Auth reads an OIDC provider's settings from its issuer, and only from origins you trust:

server/auth.config.ts
export default defineServerAuth({
  trustedOrigins: ['https://your-org.okta.com', 'https://login.microsoftonline.com']
})

Run Better Auth's migrations

The plugin adds an ssoProvider table.

Turn on domainVerification in production. Without it, anyone who registers a provider for a domain can sign in people with that domain's emails.

Signing in

The sign-in page gets a "Sign in with SSO" button. People type either:

  • their work email: the provider is found by the email's domain;
  • their organization's slug: the organization's provider is used.

They're sent to their identity provider, and come back signed in. New users land on the account page, and a provider that fails comes back with a message.

People who sign in through an organization's provider join that organization, with defaultRole or the role getRole gives them (see Who joins as what).

Setting up a provider

Each organization's page gets an SSO tab, for its owners and admins (Better Auth allows only those roles).

Adding one

Add provider asks for:

FieldOIDCSAML
Provider IDA name for it, part of its addresses (acme-okta)Same
Email domainsWhose users sign in with it, comma-separatedSame
IssuerThe provider's issuer URL; the rest is read from itYour app's entity ID for the provider
CredentialsClient ID and client secretSign-on URL, then the metadata XML, or its entity ID and certificate

More settings has the rest: scopes, PKCE, token authentication, audience, NameID format, algorithms, signed assertions and requests, profile mapping, and your own provider fields.

What to give the identity provider

Each provider on the tab shows the addresses its identity provider needs, with copy buttons:

  • OIDC: the redirect URI, https://your-site/api/auth/sso/callback/<provider id>.
  • SAML: the ACS URL, https://your-site/api/auth/sso/saml2/sp/acs/<provider id>, and a link to the service provider metadata XML.

Verifying the domain

With domainVerification, a new provider can't sign anyone in until its domains are verified:

  1. The tab shows a TXT record to add to each domain's DNS: its name, _better-auth-token-<provider id>.<domain>, and Show the value.
  2. Add the record, and wait for DNS to update.
  3. Press Verify domain.

Editing and deleting

Edit a provider from its card; fields left empty, like secrets and certificates, stay as they are. Deleting asks first: its members can't sign in through it any more.

Who joins as what

Members who sign in through their organization's provider join it with organizationProvisioning.defaultRole. To decide per person, from what the provider says about them, write getRole in a file and point serverOptions at it:

export default defineNuxtConfig({
  betterAuthUi: {
    sso: {
      enabled: true,
      organizationProvisioning: { defaultRole: 'member' },
      serverOptions: './server/auth/sso.ts'
    }
  }
})

The same file takes Better Auth's other function options: provisionUser, resolveUser, guardProviderMutation, resolvePrivateKey and defaultSSO.

In the admin

A Single sign-on page lists every provider: its protocol, domains and whether they're verified, its organization, and who added it. It never shows secrets. The configuration page shows whether SSO and domain verification are on.

Options

enabled
booleandefault: false
domainVerification
boolean | objectdefault: false
New providers work once a DNS TXT record proves the domain. { tokenPrefix } changes the record's prefix (better-auth-token).
organizationProvisioning
object
{ defaultRole: 'member' } is the role people join with; { disabled: true } stops them joining.
providersLimit
numberdefault: 10
Providers a user can register. 0 turns registering off.
disableImplicitSignUp
booleandefault: false
SSO sign-ins don't create new users unless sign-up is requested.
defaultOverrideUserInfo
booleandefault: false
Every sign-in updates the user's profile from the provider.
provisionUserOnEveryLogin
booleandefault: false
Run provisionUser (from serverOptions) on every sign-in, not just the first.
redirectURI
string
One redirect URI for every OIDC provider, for example /sso/callback. By default each has its own.
saml
object
SAML security: enableInResponseToValidation, allowIdpInitiated, requestTTL, clockSkew, requireTimestamps, idpInitiatedCallbackUrl.
schema
object
Better Auth's schema options for the ssoProvider table, including your own fields (additionalFields), which the SSO tab shows and edits.
serverOptions
string
A file with more of the plugin's options, for those that are functions.
Better Auth Infrastructure (@better-auth/infra) is a hosted, paid service with its own self-service SSO dashboard. The module doesn't add it; if you use it, add its plugins to your auth config yourself.