1---
2name: better-auth
3description: |
4 Self-hosted TypeScript auth framework with social auth, 2FA, passkeys, organizations, RBAC, and 15+ plugins. Supports Drizzle/Prisma/Kysely adapters. Self-hosted alternative to Clerk/Auth.js.
5
6 Use when: configuring auth, adding plugins, social OAuth, multi-tenant SaaS, organizations with teams and RBAC, two-factor authentication (TOTP/OTP/backup codes), email verification, password reset flows, session management, rate limiting, CSRF and cookie security, Expo/mobile, D1 adapter errors, TanStack Start integration, additionalFields bugs, admin plugin, migrating from NextAuth, migrating from Clerk, migrating from Supabase Auth, or troubleshooting auth issues.
7license: MIT
8metadata:
9 author: oakoss
10 version: '1.2'
11user-invocable: false
12---
13
14# better-auth
15
16**Package**: better-auth@1.4.15 (ESM-only since v1.4.0)
17**Docs**: <https://better-auth.com/docs> | **GitHub**: <https://github.com/better-auth/better-auth>
18
19## Environment Setup
20
21| Variable | Purpose |
22| -------------------- | --------------------------------------------------------------------- |
23| `BETTER_AUTH_SECRET` | Encryption secret (min 32 chars). Generate: `openssl rand -base64 32` |
24| `BETTER_AUTH_URL` | Base URL (e.g., `https://example.com`) |
25
26Only define `baseURL`/`secret` in config if env vars are NOT set. CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or `./src`.
27
28## Core Config Options
29
30| Option | Notes |
31| ------------------ | --------------------------------------------- |
32| `appName` | Optional display name |
33| `baseURL` | Only if `BETTER_AUTH_URL` not set |
34| `basePath` | Default `/api/auth`. Set `/` for root. |
35| `secret` | Only if `BETTER_AUTH_SECRET` not set |
36| `database` | Required unless using stateless mode (v1.4+) |
37| `secondaryStorage` | Redis/KV for sessions and rate limits |
38| `emailAndPassword` | `{ enabled: true }` to activate |
39| `socialProviders` | `{ google: { clientId, clientSecret }, ... }` |
40| `plugins` | Array of plugins |
41| `trustedOrigins` | CSRF whitelist |
42
43## Plugin Reference
44
45| Plugin | Description |
46| ------------- | ---------------------------------------------------------------------------------- |
47| twoFactor | TOTP, email OTP, backup codes |
48| organization | Multi-tenant orgs, teams, invitations, RBAC |
49| admin | User management, impersonation, banning |
50| passkey | WebAuthn passwordless login |
51| magicLink | Email-based passwordless login |
52| jwt | JWT tokens with key rotation, JWKS |
53| oauthProvider | Build your own OAuth 2.1 provider (separate `@better-auth/oauth-provider` package) |
54| sso | Enterprise SSO with OIDC, OAuth2, SAML 2.0 (separate `@better-auth/sso` package) |
55| scim | Enterprise user provisioning (separate `@better-auth/scim` package) |
56| stripe | Payment and subscription management |
57| bearer | API token auth for mobile/CLI |
58| apiKey | Token-based auth with rate limits |
59| oneTap | Google One Tap frictionless sign-in |
60| anonymous | Guest user access without PII |
61| genericOAuth | Custom OAuth providers with PKCE |
62| emailOTP | Email-based one-time password auth |
63| phoneNumber | Phone/SMS-based OTP sign-in |
64| username | Username-based sign-in (alternative to email) |
65| multiSession | Multiple accounts in same browser |
66| openAPI | Interactive API docs at `/api/auth/reference` |
67
68## Session Strategies
69
70| Strategy | Format | Use Case |
71| ----------------- | ----------------------- | ----------------- |
72| Compact (default) | Base64url + HMAC-SHA256 | Smallest, fastest |
73| JWT | Standard JWT | Interoperable |
74| JWE | A256CBC-HS512 encrypted | Most secure |
75
76## Getting Started
77
78For new projects or first-time Better Auth setup, use the official interactive setup skill:
79
80```bash
81npx skills add better-auth/skills -s create-auth-skill
82```
83
84This walks through framework detection, database selection, auth method choices, plugin setup, and generates the initial configuration.
85
86## Anti-Patterns
87
88| Anti-Pattern | Correct Approach |
89| ---------------------------------------- | ------------------------------------------------------------------------------ |
90| Using `d1Adapter` | Use Drizzle or Kysely adapter with `provider: "sqlite"` |
91| Using table name in config | Use ORM model name, not DB table name |
92| Forgetting CLI after plugin changes | Re-run `npx @better-auth/cli@latest generate` |
93| `tanstackStartCookies()` not last plugin | Must be the last plugin in array (TanStack Start) |
94| Checking `session` for login state | Check `session?.user` — session object is always truthy |
95| Missing `nodejs_compat` flag | Required in `wrangler.toml` for Cloudflare Workers |
96| Kysely CamelCasePlugin with auth | Use separate Kysely instance without the plugin |
97| Using old `reactStartCookies` import | Renamed to `tanstackStartCookies` from `better-auth/tanstack-start` in v1.4.14 |
98
99## Common Mistakes
100
101| Mistake | Correct Pattern |
102| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
103| Setting `baseURL` and `secret` in config when env vars are already set | Only define these in config if `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` env vars are NOT set |
104| Using CommonJS require syntax with better-auth v1.4+ | better-auth is ESM-only since v1.4.0; use `import` syntax exclusively |
105| Not re-running CLI generate after adding or changing plugins | Always run `npx @better-auth/cli@latest generate` after plugin changes to update DB schema |
106| Checking `session` object truthy state for login detection | Check `session?.user` instead; the session object itself is always truthy |
107| Using `d1Adapter` directly for Cloudflare D1 | Use Drizzle or Kysely adapter with `provider: "sqlite"` for D1 compatibility |
108
109## Breaking Changes
110
111| Version | Change |
112| ------- | ------------------------------------------------------------------------------------------------ |
113| v1.4.14 | `reactStartCookies` renamed to `tanstackStartCookies` (import from `better-auth/tanstack-start`) |
114| v1.4.6 | `allowImpersonatingAdmins` defaults to `false` |
115| v1.4.0 | ESM-only (no CommonJS); SSO, SCIM, OAuth Provider moved to separate packages |
116| v1.3.0 | Multi-team table structure: new `teamMembers` table needed |
117
118## Delegation
119
120When working on auth, delegate to:
121
122- `application-security` — Security architecture and threat modeling
123- `database` — Drizzle ORM schema and migrations
124- `tanstack-start` — TanStack Start integration patterns
125
126## Resources
127
128- **Docs**: <https://better-auth.com/docs>
129- **Options Reference**: <https://better-auth.com/docs/reference/options>
130- **LLMs.txt**: <https://better-auth.com/llms.txt>
131- **Changelog**: <https://www.better-auth.com/changelogs>
132- **TanStack Start**: <https://www.better-auth.com/docs/integrations/tanstack>
133- **Expo**: <https://www.better-auth.com/docs/integrations/expo>
134
135## References
136
137- [Database Adapters](references/database-adapters.md) — Drizzle, Kysely, Prisma adapters, Cloudflare Workers factory pattern
138- [Session Management](references/sessions.md) — Cookie cache, stateless sessions, storage priority, freshAge constraints
139- [Plugins and Social Auth](references/plugins.md) — Plugin setup, OAuth 2.1 provider, admin RBAC, social provider scopes
140- [Email and Password](references/email-password.md) — Verification, password reset, timing attack prevention, hashing (scrypt, argon2), token security
141- [Two-Factor Authentication](references/two-factor.md) — TOTP, email/SMS OTP, backup codes, trusted devices, 2FA session flow
142- [Organizations](references/organizations.md) — Multi-tenant orgs, teams, invitations, RBAC, dynamic access control, lifecycle hooks
143- [Configuration](references/configuration.md) — User/account config, rate limiting, hooks, CSRF, trusted origins, cookie/OAuth security, production checklist
144- [Framework Integration](references/frameworks.md) — TanStack Start setup, Expo/React Native, client imports, type safety
145- [Migration Guides](references/migration-guides.md) — Migrate from NextAuth/Auth.js, Clerk, or Supabase Auth with schema mappings and session strategies
146- [Troubleshooting](references/troubleshooting.md) — D1 consistency, CORS, OAuth redirect, admin 403, nanostore refresh, known bugs