better-auth
Skill for integrating Better Auth - comprehensive TypeScript authentication framework for Cloudflare D1, Next.js, Nuxt, and 15+ frameworks. Use when adding auth, encountering D1 adapter errors, or implementing OAuth/2FA/RBAC features.
git clone --depth 1 https://github.com/secondsky/claude-skills /tmp/better-auth && cp -r /tmp/better-auth/plugins/better-auth/skills/better-auth ~/.claude/skills/better-authSKILL.md
# better-auth
**Status**: Production Ready
**Last Updated**: 2026-04-08
**Package**: `better-auth@1.6.0` (ESM-only)
**Dependencies**: Drizzle ORM or Kysely (required for D1 complex use cases; D1 native support available in v1.5+)
---
## Quick Start (5 Minutes)
### Installation
**Option 1: Drizzle ORM (Recommended)**
```bash
bun add better-auth drizzle-orm drizzle-kit
```
**Option 2: Kysely**
```bash
bun add better-auth kysely @noxharmonium/kysely-d1
```
### ⚠️ v1.4.0+ Requirements
better-auth v1.4.0+ is **ESM-only**. Ensure:
**package.json**:
```json
{
"type": "module"
}
```
**Upgrading from v1.3.x?** Load `references/migration-guide-1.4.0.md`
**Upgrading from v1.4.x?** Load `references/migration-guide-1.5.0.md`
### ⚠️ CRITICAL: D1 Adapter Requirements
**v1.5.0+**: D1 is now natively supported. Pass your D1 binding directly:
```typescript
// ✅ SIMPLEST - D1 native (v1.5.0+)
import { betterAuth } from "better-auth";
const auth = betterAuth({
database: env.DB, // D1 binding, auto-detected
});
```
For complex schemas, use Drizzle ORM:
```typescript
// ✅ RECOMMENDED for complex schemas - Drizzle
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/d1";
const auth = betterAuth({
database: drizzleAdapter(drizzle(env.DB, { schema }), { provider: "sqlite" }),
});
```
```typescript
// ❌ WRONG - This doesn't exist
import { d1Adapter } from 'better-auth/adapters/d1'
```
### Minimal Setup (Cloudflare Workers + Drizzle)
**1. Create D1 Database:**
```bash
wrangler d1 create my-app-db
```
**2. Define Schema** (`src/db/schema.ts`):
```typescript
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const user = sqliteTable("user", {
id: text().primaryKey(),
name: text().notNull(),
email: text().notNull().unique(),
emailVerified: integer({ mode: "boolean" }).notNull().default(false),
image: text(),
});
export const session = sqliteTable("session", {
id: text().primaryKey(),
userId: text().notNull().references(() => user.id, { onDelete: "cascade" }),
token: text().notNull(),
expiresAt: integer({ mode: "timestamp" }).notNull(),
});
// See references/database-schema.ts for complete schema
```
**3. Initialize Auth** (`src/auth.ts`):
```typescript
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/d1";
import * as schema from "./db/schema";
export function createAuth(env: { DB: D1Database; BETTER_AUTH_SECRET: string }) {
const db = drizzle(env.DB, { schema });
return betterAuth({
baseURL: env.BETTER_AUTH_URL,
secret: env.BETTER_AUTH_SECRET,
database: drizzleAdapter(db, { provider: "sqlite" }),
emailAndPassword: { enabled: true },
});
}
```
**4. Create Worker** (`src/index.ts`):
```typescript
import { Hono } from "hono";
import { createAuth } from "./auth";
const app = new Hono<{ Bindings: Env }>();
app.all("/api/auth/*", async (c) => {
const auth = createAuth(c.env);
return auth.handler(c.req.raw);
});
export default app;
```
**5. Deploy:**
```bash
bunx drizzle-kit generate
wrangler d1 migrations apply my-app-db --remote
wrangler deploy
```
---
## Decision Tree
**For code examples and syntax, always consult [better-auth.com/docs](https://better-auth.com/docs).**
```
Is this a new/empty project?
├─ YES → New project setup
│ 1. Identify framework (Next.js, Nuxt, Workers, etc.)
│ 2. Choose database (D1, PostgreSQL, MongoDB, MySQL)
│ 3. Install better-auth + Drizzle/Kysely
│ 4. Create auth.ts + auth-client.ts
│ 5. Set up route handler (see Quick Start above)
│ 6. Run migrations (Drizzle Kit for D1)
│ 7. Add features via plugins (2FA, organizations, etc.)
│
└─ NO → Does project have existing auth?
├─ YES → Migration/enhancement
│ • Audit current auth for gaps
│ • Plan incremental migration
│ • See references/framework-comparison.md for migration guides
│
└─ NO → Add auth to existing project
1. Analyze project structure
2. Install better-auth + adapter
3. Create auth config (see Quick Start)
4. Add route handler to existing routes
5. Run schema migrations
6. Integrate into existing pages/components
```
---
## Critical Rules
### MUST DO
✅ Use `better-auth/minimal` + adapter packages for smallest bundle (v1.5+)
✅ Use `npx auth migrate` and `npx auth generate` for CLI commands (v1.5+)
✅ Set BETTER_AUTH_SECRET via `wrangler secret put`
✅ Configure CORS with `credentials: true`
✅ Match OAuth callback URLs exactly (no trailing slash)
✅ Apply migrations to local D1 before `wrangler dev`
✅ Use camelCase column names in schema
### NEVER DO
❌ Use `d1Adapter` (doesn't exist)
❌ Forget CORS credentials or mismatch OAuth URLs
❌ Use snake_case columns without CamelCasePlugin
❌ Skip local migrations or hardcode secrets
❌ Leave sendVerificationEmail unimplemented
### ⚠️ v1.5.0 Breaking Changes
**API Key Plugin Moved**:
```typescript
- import { apiKey } from "better-auth/plugins";
+ import { apiKey } from "@better-auth/api-key";
```
Schema: `userId` → `referenceId`, new `configId` field.
**After Hooks**: Database after-hooks now run post-transaction (not inside it).
**Deprecated APIs Removed**: `Adapter` → `DBAdapter`, `InferUser`/`InferSession` removed, `@better-auth/core/utils` split into subpath exports.
**Load `references/migration-guide-1.5.0.md` when upgrading from <1.5.0**
### ⚠️ v1.6.0 Breaking Changes
**Session Freshness**: `freshAge` now uses `createdAt` (not `updatedAt`). Sessions may require re-auth more frequently for sensitive operations.
**SAML Security**: InResponseTo validation is **default ON**. Opt out with `saml: { enableInResponseToValidation: false }`.
**OIDC Provider Deprecated**: Use `@better-auth/oauth-provider` instead.
### New in v1.5.0 (Highlights)
- **New CLI**: `npx auth init/migrate/generate/upgrade`
- **D1 Native**: Pass D1 binding directly (no adaRole-based access control (RBAC) with permissions and policies. Use for admin dashboards, enterprise access, multi-tenant apps, fine-grained authorization, or encountering permission hierarchies, role inheritance, policy conflicts.
100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or encountering animation, shadcn CLI integration errors.
shadcn/ui AI chat components for conversational interfaces. Use for streaming chat, tool/function displays, reasoning visualization, or encountering Next.js App Router setup, Tailwind v4 integration, AI SDK v5 migration errors.
Vercel AI SDK v5 for backend AI (text generation, structured output, tools, agents). Multi-provider. Use for server-side AI or encountering AI_APICallError, AI_NoObjectGeneratedError, streaming failures.
Vercel AI SDK v5 React hooks (useChat, useCompletion, useObject) for AI chat interfaces. Use for React/Next.js AI apps or encountering parse stream errors, no response, streaming issues.
Secure API authentication with JWT, OAuth 2.0, API keys. Use for authentication systems, third-party integrations, service-to-service communication, or encountering token management, security headers, auth flow errors.
Creates comprehensive API changelogs documenting breaking changes, deprecations, and migration strategies for API consumers. Use when managing API versions, communicating breaking changes, or creating upgrade guides.
Verifies API contracts between services using consumer-driven contracts, schema validation, and tools like Pact. Use when testing microservices communication, preventing breaking changes, or validating OpenAPI specifications.