
Better Auth Best Practices
Wire up Better Auth in a TypeScript app with database adapters, sessions, plugins, and env-based secrets without guessing the setup order.
Install
npx skills add https://github.com/better-auth/skills --skill better-auth-best-practicesWhat is this skill?
- 6-step setup workflow from install through `GET /api/auth/ok` verification
- Env vars `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL` with optional in-config overrides
- CLI: migrate, generate (Prisma/Drizzle), and MCP via `@better-auth/cli`
- Plugin and adapter changes require re-running migrate/generate
- Official docs at better-auth.com/docs are the source of truth for API examples
Adoption & trust: 56k installs on skills.sh; 196 GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Entra App Registrationmicrosoft/azure-skills
Azure Aigatewaymicrosoft/azure-skills
Lark Openapi Explorerlarksuite/cli
Supabasesupabase/agent-skills
Firebase Auth Basicsfirebase/agent-skills
Firebase Data Connectfirebase/agent-skills
Journey fit
Common Questions / FAQ
Is Better Auth Best Practices safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Better Auth Best Practices
# Better Auth Integration Guide **Always consult [better-auth.com/docs](https://better-auth.com/docs) for code examples and latest API.** --- ## Setup Workflow 1. Install: `npm install better-auth` 2. Set env vars: `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL` 3. Create `auth.ts` with database + config 4. Create route handler for your framework 5. Run `npx @better-auth/cli@latest migrate` 6. Verify: call `GET /api/auth/ok` — should return `{ status: "ok" }` --- ## Quick Reference ### Environment Variables - `BETTER_AUTH_SECRET` - Encryption secret (min 32 chars). Generate: `openssl rand -base64 32` - `BETTER_AUTH_URL` - Base URL (e.g., `https://example.com`) Only define `baseURL`/`secret` in config if env vars are NOT set. ### File Location CLI looks for `auth.ts` in: `./`, `./lib`, `./utils`, or under `./src`. Use `--config` for custom path. ### CLI Commands - `npx @better-auth/cli@latest migrate` - Apply schema (built-in adapter) - `npx @better-auth/cli@latest generate` - Generate schema for Prisma/Drizzle - `npx @better-auth/cli mcp --cursor` - Add MCP to AI tools **Re-run after adding/changing plugins.** --- ## Core Config Options | Option | Notes | |--------|-------| | `appName` | Optional display name | | `baseURL` | Only if `BETTER_AUTH_URL` not set | | `basePath` | Default `/api/auth`. Set `/` for root. | | `secret` | Only if `BETTER_AUTH_SECRET` not set | | `database` | Required for most features. See adapters docs. | | `secondaryStorage` | Redis/KV for sessions & rate limits | | `emailAndPassword` | `{ enabled: true }` to activate | | `socialProviders` | `{ google: { clientId, clientSecret }, ... }` | | `plugins` | Array of plugins | | `trustedOrigins` | CSRF whitelist | --- ## Database **Direct connections:** Pass `pg.Pool`, `mysql2` pool, `better-sqlite3`, or `bun:sqlite` instance. **ORM adapters:** Import from `better-auth/adapters/drizzle`, `better-auth/adapters/prisma`, `better-auth/adapters/mongodb`. **Critical:** Better Auth uses adapter model names, NOT underlying table names. If Prisma model is `User` mapping to table `users`, use `modelName: "user"` (Prisma reference), not `"users"`. --- ## Session Management **Storage priority:** 1. If `secondaryStorage` defined → sessions go there (not DB) 2. Set `session.storeSessionInDatabase: true` to also persist to DB 3. No database + `cookieCache` → fully stateless mode **Cookie cache strategies:** - `compact` (default) - Base64url + HMAC. Smallest. - `jwt` - Standard JWT. Readable but signed. - `jwe` - Encrypted. Maximum security. **Key options:** `session.expiresIn` (default 7 days), `session.updateAge` (refresh interval), `session.cookieCache.maxAge`, `session.cookieCache.version` (change to invalidate all sessions). --- ## User & Account Config **User:** `user.modelName`, `user.fields` (column mapping), `user.additionalFields`, `user.changeEmail.enabled` (disabled by default), `user.deleteUser.enabled` (disabled by default). **Account:** `account.modelName`, `account.accountLinking.enabled`, `account.storeAccountCookie` (for stateless OAuth). **Required for registration:** `email` and `name` fields. --- ## Email Flows - `emailVerification.sendVerificationEmail` - Must be defined for verification to work - `emailVerification.sendOnSignUp` / `sendOnSignIn` - Auto-send triggers - `emailAndPassword.sendResetPassword` - Password reset email handler --- ## Security **In `advanced`:** - `useSecureCookies` - Force HTTPS cookies - `disableCSRFCheck` - ⚠️ Security risk - `disableOriginCheck` - ⚠️ Security risk - `crossSubDomainCookies.enabled` - Share cookies across subdomains - `ipAddress.ipAddressHeader