Back to Security & Vulnerability Analysis

better-auth-best-practices

authenticationsecuritytypescriptauth frameworkpasswordlessoauthclibest practices
198🕒 2026-03-02Source ↗

Install this skill

npx skills add better-auth/skills

Works 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

  1. Set BETTER_AUTH_SECRET and BETTER_AUTH_URL environment variables
  2. Initialize auth instance in auth.ts with required database adapter
  3. Run npx @better-auth/cli generate to sync schema with your ORM
  4. Apply required plugins like twoFactor or magicLink to the config object
  5. Mount the auth handler to the API route
  6. 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

Should I store sessions in the database or Redis?
Use the database for simple setups to maintain referential integrity. Use secondary storage like Redis when handling high-concurrency applications where database write latency must be avoided.
Can I use Better Auth without a database?
Yes, by configuring cookieCache strategies, you can achieve a fully stateless authentication mode, though some plugin features may be restricted.
Why is my database sync failing?
Ensure your ORM model names match the identity expected by the adapter, not the underlying table names in your database.
How do I invalidate all active sessions?
Update the session.cookieCache.version in your configuration to force a rotation that invalidates existing cookies.

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.

Source & trust

198 stars🕒 Updated 2026-03-02
📄 Full skill instructions — original source: better-auth/skills
# Better Auth Integration Guide

**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 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.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)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/best-practices/
  3. Save the file as SKILL.md
  4. 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

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid security & vulnerability analysis issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Security & Vulnerability Analysis and is published by Better Auth, maintained in better-auth/skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.