Skip to content

[feature] add generic OIDC authentication (Okta, Auth0, Keycloak, OneLogin, ...) #684

@d-axel-b

Description

@d-axel-b

Summary

Adds SSO login via any OIDC-compliant identity provider using better-auth's genericOAuth plugin. One integration that works with Okta, Auth0, Keycloak, OneLogin, and any provider that exposes a standard OIDC discovery document.

Configuration

Set the following environment variables to enable:

  • OIDC_DISCOVERY_URL (required) — provider's .well-known/openid-configuration URL
  • OIDC_CLIENT_ID (required)
  • OIDC_CLIENT_SECRET (required)
  • OIDC_PROVIDER_ID — defaults to oidc, used in callback URL and button logic
  • OIDC_PROVIDER_NAME — defaults to SSO, shown on the login button
  • OIDC_SCOPES — defaults to openid,profile,email
  • OIDC_AUTH_DOMAINS — optional comma-separated email domain allowlist
  • OIDC_PKCE — defaults to true

When unset, the SSO button is hidden.

Redirect URI to register in your IdP: https://<your-nao-host>/api/auth/oauth2/callback/{OIDC_PROVIDER_ID}

What's included

  • Backend: genericOAuth plugin registration, env schema (8 vars), domain allowlist enforcement in databaseHooks.user.create.before, OIDC users included in isSocial check for auto-provisioning, tRPC authConfig.oidc.getConfig endpoint
  • Frontend: genericOAuthClient plugin, dynamic handleOidcSignIn via signIn.oauth2, conditional "Continue with {providerName}" button with LockKeyholeIcon
  • Docs: setup guide at apps/backend/docs/auth-oidc.md with walkthroughs for Okta, Auth0, Keycloak, and OneLogin
  • Tests: 15 Vitest unit tests — 10 for domain allowlist edge cases, 5 for tRPC endpoint

Test plan

  • npm run lint passes (no new errors — pre-existing drizzle-orm type issues unrelated)
  • npm test passes (15/15 new tests pass)
  • Manual smoke against an OIDC provider:
    • New user with allowed domain → user + account rows created, session set, redirected to /
    • Returning user → no new user row, existing session restored
    • Domain not in allowlist → generic auth error, no user row created
    • SSO button visible when env vars set, hidden when unset
    • Custom provider name displayed on button
    • Coexistence with Google/GitHub auth

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions