Authentication System#
LobeHub's self-hosted authentication is built on Better Auth. The central configuration lives in src/libs/better-auth/define-config.ts, which assembles the full Better Auth instance from environment-driven options, database adapters, plugins, and SSO providers.
Authentication strategies are entirely controlled through environment variables — no code changes are needed to switch between modes. All auth env vars are declared and validated (via Zod + @t3-oss/env-core) in packages/env/src/auth.ts.
Authentication Modes#
Email/Password (default)#
Email/password login is enabled by default . The Better Auth config exposes it via the emailAndPassword block:
- Passwords are 8–64 characters
- Bcrypt hashes from Clerk migrations are supported alongside Better Auth's default scrypt
- Email verification is opt-in via
AUTH_EMAIL_VERIFICATION=1 - Magic link (passwordless) login is opt-in via
AUTH_ENABLE_MAGIC_LINK=1; expires in 15 minutes - Password-reset and verification emails require SMTP configuration
SSO-Only Mode#
Setting AUTH_DISABLE_EMAIL_PASSWORD=1 disables email/password login entirely . When active :
- The email field is hidden on the login page
- The signup page redirects to login
- Users must authenticate through a configured SSO provider
⚠️ Ensure at least one SSO provider is configured via
AUTH_SSO_PROVIDERSbefore enabling SSO-only mode, or users will have no login path .
SSO Provider Configuration#
Providers are enabled by setting AUTH_SSO_PROVIDERS to a comma-separated list of provider IDs . The order determines display order on the login page.
Supported providers (each requires a corresponding AUTH_<PROVIDER>_ID / AUTH_<PROVIDER>_SECRET, and OIDC providers also need AUTH_<PROVIDER>_ISSUER) :
| Category | Providers |
|---|---|
| Social / OAuth | Google, GitHub, Apple, Microsoft, WeChat, Feishu |
| OIDC / Enterprise | Auth0, Authelia, Authentik, Casdoor, Cloudflare Zero Trust, Cognito, Keycloak, Logto, Okta, Zitadel |
| Generic OIDC | generic_oidc (via AUTH_GENERIC_OIDC_*) |
Internally, initBetterAuthSSOProviders() resolves each provider name against a registry, validates required env vars, and routes them to either socialProviders (built-in) or genericOAuthProviders (OIDC). The parsed provider list is also used as the trustedProviders for account linking, allowing accounts with different emails to be merged .
Key Environment Variables#
| Variable | Required | Default | Purpose |
|---|---|---|---|
AUTH_SECRET | ✅ | — | Session token encryption key |
JWKS_KEY | ✅ | — | RS256 RSA key pair for OIDC JWT signing and internal service auth |
AUTH_SSO_PROVIDERS | Optional | "" | Comma-separated list of enabled providers |
AUTH_DISABLE_EMAIL_PASSWORD | Optional | 0 | 1 = SSO-only mode |
AUTH_EMAIL_VERIFICATION | Optional | 0 | 1 = require email verification on signup |
AUTH_ENABLE_MAGIC_LINK | Optional | 0 | 1 = enable passwordless magic link login |
AUTH_ALLOWED_EMAILS | Optional | — | Comma-separated emails/domains allowed to register |
AUTH_TRUSTED_ORIGINS | Optional | — | Additional trusted origins for CSRF/CORS |
INTERNAL_JWT_EXPIRATION | Optional | 30s | Expiry for internal lambda→async JWT tokens |
Full variable reference: docs/self-hosting/environment-variables/auth.mdx
Additional Features#
Passkeys — enabled unconditionally via the @better-auth/passkey plugin; rpID and origin are derived from APP_URL .
Email OTP (mobile) — the emailOTP plugin issues 6-digit codes expiring in 5 minutes for Expo/React Native clients; OTP is not auto-sent on signup .
Email whitelist — the custom emailWhitelist() plugin enforces AUTH_ALLOWED_EMAILS at user-creation time for both email signup and SSO flows, blocking registration with an EMAIL_NOT_ALLOWED error for unauthorized emails .
Session storage — sessions are stored both in PostgreSQL (via Drizzle) and a Redis secondary storage for performance; cookie-level cache has a 2-minute TTL .
User bootstrap — a databaseHooks.user.create.after hook calls UserService.initUser() for every new account regardless of sign-up method .
Rate limiting — password-reset and email-verification endpoints are capped at 3 requests per 60 seconds .
Key Source Files#
| File | Purpose |
|---|---|
src/libs/better-auth/define-config.ts | Main Better Auth config factory |
packages/env/src/auth.ts | All auth env var declarations & Zod schemas |
docs/self-hosting/environment-variables/auth.mdx | Operator-facing env var reference |
docs/self-hosting/auth/providers/password.mdx | Email/password & SSO-only mode guide |