Skip to content

SSO (OIDC)

OIDC federation: register external identity providers per domain or organization and route /sign-in/sso to the right one, with SSRF-guarded discovery, optional DNS TXT domain verification and user/organization provisioning. Mirrors the OIDC half of the TS @better-auth/sso plugin — SAML is out of scope in this port.

Enable

python
from better_auth import BetterAuth
from better_auth.plugins_ext import SSOPlugin

auth = BetterAuth(
    secret="a-strong-32-character-minimum-secret",
    plugins=[SSOPlugin(trust_email_verified=False)],
)

Options

OptionTypeDefaultDescription
providers_limitint | callable | NoneNoneMax providers a user may register.
default_override_user_infoboolFalseOverwrite user fields from the IdP on every login by default.
default_ssolist[dict] | NoneNoneStatically configured providers (no DB row).
domain_verificationdict | NoneNoneEnable DNS TXT domain verification (needs the sso extra: dnspython).
redirect_uristr | NoneNoneOverride the callback URL registered with IdPs.
model_namestr | NoneNone ("ssoProvider")Table name override.
fieldsdict[str, str] | NoneNoneColumn-name overrides.
provision_usercallable | NoneNone(payload) -> None, runs when a user is provisioned.
provision_user_on_every_loginboolFalseRe-run provisioning on every login.
organization_provisioningdict | NoneNoneAuto-assign users to an organization on SSO login.
trust_email_verifiedboolFalseTrust the IdP's email_verified claim.
disable_implicit_sign_upboolFalseNever create users implicitly on SSO sign-in.
resolve_host / dns_resolvercallable | NoneNoneTest seams for the SSRF guard and DNS lookups.

Endpoints

MethodPath
POST/sign-in/sso
GET/sso/callback/{providerId}
GET/sso/callback
POST/sso/register
GET/sso/providers
GET/sso/get-provider
POST/sso/update-provider
POST/sso/delete-provider

Schema

TableColumns
ssoProviderissuer, oidcConfig, samlConfig, userId, providerId, organizationId, domain (+ domainVerified when domain_verification is enabled)

Notes

  • samlConfig is retained as a nullable column for cross-runtime DB compatibility only; a providerType: "saml" registration body is rejected.
  • clientSecret is stored in the oidcConfig JSON in plaintext — a deliberate cross-runtime contract (the secret is needed cleartext at every token exchange); it is masked on read.
  • For a single hand-configured OAuth2/OIDC provider without per-domain routing, Generic OAuth is the lighter tool.

MIT licensed · API-compatible with better-auth