Skip to content

Add OIDC single sign-on (Authentik) with email-based account mapping - #39

Merged
MacNite merged 1 commit into
mainfrom
sso-oidc
Oct 7, 2026
Merged

MacNite merged 1 commit into
mainfrom
sso-oidc

Conversation

@MacNite

@MacNite MacNite commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Summary

Adds single sign-on via OpenID Connect, built for Authentik, on top of Better Auth's genericOAuth plugin. Users are matched to existing Hive Pal accounts by email address (not case-sensitive).

Configuration (env vars only)

Variable Purpose Default
OIDC_ISSUER / OIDC_DISCOVERY_URL Provider (Authentik: https://auth.example.com/application/o/<slug>/) —
OIDC_CLIENT_ID, OIDC_CLIENT_SECRET Client credentials —
OIDC_PROVIDER_ID Used in redirect URI <BETTER_AUTH_URL>/api/auth/oauth2/callback/<id> authentik
OIDC_SCOPES Scopes requested from the provider openid profile email
OIDC_BUTTON_LABEL Login button text Sign in with SSO
OIDC_ALLOW_SIGNUP Create unknown users on first SSO login true
DISABLE_LOCAL_LOGIN SSO only: blocks password, magic-link and passkey sign-in and email sign-up; ignored unless OIDC is configured false

SSO turns on once issuer (or discovery URL), client ID and secret are all set. The frontend reads the non-secret flags at runtime from the existing /env.js.

Account linking & security

  • The provider's email claim is trusted even when email_verified is false, since Authentik is self-hosted and admin-controlled.
  • Hive Pal has no email-verification step, so requireLocalEmailVerified is off. To prevent account pre-hijacking, an implicit link to an account with an unverified email removes that account's password credential, its passkeys and any sessions created before the link. The data stays; the owner can set a new password via "forgot password". The email is then marked verified.
  • When a signed-in owner links SSO from Settings, their password is kept.

Frontend

  • SSO button on the login and register pages, with error messages mapped from Better Auth's error codes. Local login UI is hidden when DISABLE_LOCAL_LOGIN is on.
  • One-time privacy-consent page (/account/consent) for SSO-created users. They skipped the signup form, so this is where they accept the privacy policy.
  • "Single sign-on" card in Settings to link and unlink. The password/passkey sections are hidden where they don't apply.
  • Translations in English and German. Other languages fall back to English.

Docs

Self-hosting configuration docs now include an Authentik setup guide, and both .env.example files list the new variables.

Testing

  • New unit tests: oidc-config.spec.ts, oidc-linking.spec.ts (13 pass). Backend and frontend typecheck clean; eslint clean on changed files.
  • Ran the real backend with local Postgres against a mock OIDC provider. All 26 checks pass:
    • new user via SSO, consent flag, returning user
    • linking an existing verified account with different email casing
    • pre-hijack case: password and old sessions removed, new SSO session kept
    • manual link keeps the password
    • OIDC_ALLOW_SIGNUP=false → error=signup_disabled
    • DISABLE_LOCAL_LOGIN=true → 403 on password, signup and magic link while SSO still works
  • Clicked through login → Authentik (mock) → consent → settings in Chromium against the Vite dev server.
  • Not tested against a real Authentik instance.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XAcVdsLGq2sRWTT5CRqLw2


Generated by Claude Code

- Backend: Better Auth genericOAuth provider configured via OIDC_* env vars
  (issuer/discovery URL, client id/secret, scopes, button label).
- Users are matched to existing accounts by email; the IdP's email claim is
  trusted. When SSO is linked implicitly to an account with an unverified
  email, its password, passkeys and older sessions are removed to prevent
  account pre-hijacking. Accounts linked by their signed-in owner from
  settings keep their password.
- OIDC_ALLOW_SIGNUP toggles auto-creating unknown users on first SSO login.
- DISABLE_LOCAL_LOGIN blocks password, magic-link, passkey sign-in and
  email sign-up (ignored unless OIDC is configured).
- Frontend: SSO button on login/register pages, SSO error messages,
  one-time privacy consent page for SSO-created users, link/unlink card in
  settings; runtime config exposed through /env.js.
- Docs and env examples, including Authentik setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAcVdsLGq2sRWTT5CRqLw2
@MacNite
MacNite merged commit a5096f0 into main Oct 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants