better-auth-best-practices
Install this skill
npx skills add better-auth/skillsWorks across Claude Code, Cursor, Codex, Copilot & Antigravity
Better Auth provides a modular, type-safe authentication framework for TypeScript environments. It operates as a platform-agnostic library that handles identity management through plugins, database adapters, and hook-based lifecycle events. The architecture separates session storage, account management, and transport security, allowing developers to switch between stateless cookie caching, database-backed sessions, or external key-value stores. By enforcing strict environment configuration and utilizing a CLI tool for schema synchronization with Prisma or Drizzle, it minimizes manual boilerplate. The system supports complex workflows like multi-tenancy, passkey authentication, and multi-factor verification through tree-shakable packages. Developers can hook into both API endpoints and database operations, providing granular control over user creation, account linking, and session expiration policies without needing custom middleware for every authentication state.
When to Use This Skill
- •Implementing standardized email/password and social login flows
- •Enforcing multi-factor authentication across web applications
- •Managing complex session state across subdomains
- •Rapidly syncing database schemas with authentication requirements
- •Building organizational or multi-tenancy auth structures
How to Invoke This Skill
Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:
- “Set up Better Auth with Drizzle in my Next.js project
- “How to configure session storage in Better Auth
- “Add 2FA plugin to my Better Auth implementation
- “Troubleshoot Better Auth database schema migration
- “Create custom auth hooks for user registration
Pro Tips
- 💡Always generate a strong, minimum 32-character `BETTER_AUTH_SECRET` using secure methods like `openssl rand -base64 32` and store it securely in environment variables.
- 💡Remember to re-run `npx @better-auth/cli@latest generate` after adding or modifying any Better Auth plugins to update your schema correctly.
- 💡Prioritize using environment variables (`BETTER_AUTH_URL`, `BETTER_AUTH_SECRET`) over hardcoding `baseURL` and `secret` in your configuration file for enhanced security and deployment flexibility.
What this skill does
- •Schema generation for Prisma and Drizzle ORMs
- •Plugin-based architecture for OIDC, Passkeys, and 2FA
- •Configurable session storage priority between database, Redis, and stateless JWT cookies
- •Lifecycle hooks for custom business logic during sign-up or session validation
- •Integrated rate-limiting and CSRF protection modules
When not to use it
- ✕Projects requiring extremely minimal dependencies without TypeScript
- ✕Situations where a fully hosted Auth-as-a-Service solution is required for compliance
- ✕Apps needing legacy system integration without modern ORMs
Example workflow
- Set BETTER_AUTH_SECRET and BETTER_AUTH_URL environment variables
- Initialize auth instance in auth.ts with required database adapter
- Run npx @better-auth/cli generate to sync schema with your ORM
- Apply required plugins like twoFactor or magicLink to the config object
- Mount the auth handler to the API route
- Connect frontend client using the framework-specific client library
Prerequisites
- –Node.js environment
- –TypeScript knowledge
- –A database supported by the provided adapters
- –Defined environment variables for secret and base URL
Pitfalls & limitations
- !Confusing model names with database table names in ORM configuration
- !Forgetting to re-run the CLI generate command after modifying plugin arrays
- !Overriding default security features like CSRF checks without sufficient context
- !Incorrectly importing plugins from the barrel index instead of specific paths
FAQ
How it compares
Unlike manual implementation which requires managing raw session tokens and database queries, Better Auth provides a structured schema and hook system that ensures security configurations like CSRF and rate limiting are applied consistently.
📄 Full skill instructions — original source: better-auth/skills
**Always consult [better-auth.com/docs](https://better-auth.com/docs) for code examples and latest API.**
Better Auth is a TypeScript-first, framework-agnostic auth framework supporting email/password, OAuth, magic links, passkeys, and more via plugins.
---
## 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 DB3. 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.ipAddressHeaders - Custom IP headers for proxies-
database.generateId - Custom ID generation or "serial"/"uuid"/false**Rate limiting:**
rateLimit.enabled, rateLimit.window, rateLimit.max, rateLimit.storage ("memory" | "database" | "secondary-storage").---
## Hooks
**Endpoint hooks:**
hooks.before / hooks.after - Array of { matcher, handler }. Use createAuthMiddleware. Access ctx.path, ctx.context.returned (after), ctx.context.session.**Database hooks:**
databaseHooks.user.create.before/after, same for session, account. Useful for adding default values or post-creation actions.**Hook context (
ctx.context):** session, secret, authCookies, password.hash()/verify(), adapter, internalAdapter, generateId(), tables, baseURL.---
## Plugins
**Import from dedicated paths for tree-shaking:**
import { twoFactor } from "better-auth/plugins/two-factor"NOT
from "better-auth/plugins".**Popular plugins:**
twoFactor, organization, passkey, magicLink, emailOtp, username, phoneNumber, admin, apiKey, bearer, jwt, multiSession, sso, oauthProvider, oidcProvider, openAPI, genericOAuth.Client plugins go in
createAuthClient({ plugins: [...] }).---
## Client
Import from:
better-auth/client (vanilla), better-auth/react, better-auth/vue, better-auth/svelte, better-auth/solid.Key methods:
signUp.email(), signIn.email(), signIn.social(), signOut(), useSession(), getSession(), revokeSession(), revokeSessions().---
## Type Safety
Infer types:
typeof auth.$Infer.Session, typeof auth.$Infer.Session.user.For separate client/server projects:
createAuthClient<typeof auth>().---
## Common Gotchas
1. **Model vs table name** - Config uses ORM model name, not DB table name
2. **Plugin schema** - Re-run CLI after adding plugins
3. **Secondary storage** - Sessions go there by default, not DB
4. **Cookie cache** - Custom session fields NOT cached, always re-fetched
5. **Stateless mode** - No DB = session in cookie only, logout on cache expiry
6. **Change email flow** - Sends to current email first, then new email
---
## Resources
- [Docs](https://better-auth.com/docs)
- [Options Reference](https://better-auth.com/docs/reference/options)
- [LLMs.txt](https://better-auth.com/llms.txt)
- [GitHub](https://github.com/better-auth/better-auth)
- [Init Options Source](https://github.com/better-auth/better-auth/blob/main/packages/core/src/types/init-options.ts)
How to Use This Skill Unit
Option A: Project-Specific (Recommended)
- Click "Download" above
- In your project, create the directory:
.agent/skills/best-practices/ - Save the file as
SKILL.md - The agent will automatically discover the skill based on its description.
Option B: Global Installation (All Agents)
Save the file to these locations to make it available across all projects:
- Claude Code:
~/.claude/skills/better-auth/skills/best-practices/SKILL.md - Cursor:
~/.cursor/skills/better-auth/skills/best-practices/SKILL.md - Antigravity:
~/.gemini/antigravity/skills/better-auth/skills/best-practices/SKILL.md
🚀 Install with CLI:npx skills add better-auth/skills
