--- name: better-auth description: Guide for implementing Better Auth - a framework-agnostic authentication and authorization framework for TypeScript. Use when adding authentication features like email/password, OAuth, 2FA, passkeys, or advanced auth functionality to applications. license: MIT version: 1.0.0 --- # Better Auth Skill Better Auth is a comprehensive, framework-agnostic authentication and authorization framework for TypeScript that provides built-in support for email/password authentication, social sign-on, and a powerful plugin ecosystem for advanced features. ## When to Use This Skill Use this skill when: - Implementing authentication in TypeScript/JavaScript applications - Adding email/password or social OAuth authentication - Setting up 2FA, passkeys, magic links, or other advanced auth features - Building multi-tenant applications with organization support - Implementing session management and user management - Working with any framework (Next.js, Nuxt, SvelteKit, Remix, Astro, Hono, Express, etc.) ## Core Concepts ### Key Features - **Framework Agnostic**: Works with any framework (Next.js, Nuxt, Svelte, Remix, Hono, Express, etc.) - **Built-in Auth Methods**: Email/password and OAuth 2.0 social providers - **Plugin Ecosystem**: Easy-to-add advanced features (2FA, passkeys, magic link, username, email OTP, organization, etc.) - **Database Flexibility**: Supports SQLite, PostgreSQL, MySQL, MongoDB, and more - **ORM Support**: Built-in adapters for Drizzle, Prisma, Kysely, and MongoDB - **Type Safety**: Full TypeScript support with excellent type inference - **Session Management**: Built-in session handling for both client and server ### Architecture Better Auth follows a client-server architecture: 1. **Server Instance** (`better-auth`): Handles auth logic, database operations, and API routes 2. **Client Instance** (`better-auth/client`): Provides hooks and methods for authentication 3. **Plugins**: Extend both server and client functionality ## Installation & Setup ### Step 1: Install Package ```bash npm install better-auth # or pnpm add better-auth # or yarn add better-auth # or bun add better-auth ``` ### Step 2: Environment Variables Create `.env` file: ```env BETTER_AUTH_SECRET= BETTER_AUTH_URL=http://localhost:3000 ``` Generate secret: Use openssl or a random string generator (min 32 characters). ### Step 3: Create Auth Server Instance Create `auth.ts` in project root, `lib/`, `utils/`, or nested under `src/`, `app/`, or `server/`: ```ts import { betterAuth } from 'better-auth'; export const auth = betterAuth({ database: { // Database configuration }, emailAndPassword: { enabled: true, autoSignIn: true, // Users auto sign-in after signup }, socialProviders: { github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, }, google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }, }, }); ``` ### Step 4: Database Configuration Choose your database setup: **Direct Database Connection:** ```ts import { betterAuth } from 'better-auth'; import Database from 'better-sqlite3'; // or import { Pool } from "pg"; // or import { createPool } from "mysql2/promise"; export const auth = betterAuth({ database: new Database('./sqlite.db'), // or: new Pool({ connectionString: process.env.DATABASE_URL }) // or: createPool({ host: "localhost", user: "root", ... }) }); ``` **ORM Adapter:** ```ts // Prisma import { prismaAdapter } from 'better-auth/adapters/prisma'; import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: 'postgresql', }), }); // Drizzle import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { db } from '@/db'; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg', // or "mysql", "sqlite" }), }); // MongoDB import { mongodbAdapter } from 'better-auth/adapters/mongodb'; import { client } from '@/db'; export const auth = betterAuth({ database: mongodbAdapter(client), }); ``` ### Step 5: Create Database Schema Use Better Auth CLI: ```bash # Generate schema/migration files npx @better-auth/cli generate # Or migrate directly (Kysely adapter only) npx @better-auth/cli migrate ``` ### Step 6: Mount API Handler Create catch-all route for `/api/auth/*`: **Next.js (App Router):** ```ts // app/api/auth/[...all]/route.ts import { auth } from '@/lib/auth'; import { toNextJsHandler } from 'better-auth/next-js'; export const { POST, GET } = toNextJsHandler(auth); ``` **Nuxt:** ```ts // server/api/auth/[...all].ts import { auth } from '~/utils/auth'; export default defineEventHandler((event) => { return auth.handler(toWebRequest(event)); }); ``` **SvelteKit:** ```ts // hooks.server.ts import { auth } from '$lib/auth'; import { svelteKitHandler } from 'better-auth/svelte-kit'; export async function handle({ event, resolve }) { return svelteKitHandler({ event, resolve, auth }); } ``` **Hono:** ```ts import { Hono } from 'hono'; import { auth } from './auth'; const app = new Hono(); app.on(['POST', 'GET'], '/api/auth/*', (c) => auth.handler(c.req.raw)); ``` **Express:** ```ts import express from 'express'; import { toNodeHandler } from 'better-auth/node'; import { auth } from './auth'; const app = express(); app.all('/api/auth/*', toNodeHandler(auth)); ``` ### Step 7: Create Client Instance Create `auth-client.ts`: ```ts import { createAuthClient } from 'better-auth/client'; export const authClient = createAuthClient({ baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL || 'http://localhost:3000', }); ``` ## Authentication Methods ### Email & Password **Server Configuration:** ```ts export const auth = betterAuth({ emailAndPassword: { enabled: true, autoSignIn: true, // default: true }, }); ``` **Client Usage:** ```ts // Sign Up const { data, error } = await authClient.signUp.email( { email: 'user@example.com', password: 'securePassword123', name: 'John Doe', image: 'https://example.com/avatar.jpg', // optional callbackURL: '/dashboard', // optional }, { onSuccess: (ctx) => { // redirect or show success }, onError: (ctx) => { alert(ctx.error.message); }, } ); // Sign In const { data, error } = await authClient.signIn.email({ email: 'user@example.com', password: 'securePassword123', callbackURL: '/dashboard', rememberMe: true, // default: true }); ``` ### Social OAuth **Server Configuration:** ```ts export const auth = betterAuth({ socialProviders: { github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, }, google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }, // Other providers: apple, discord, facebook, etc. }, }); ``` **Client Usage:** ```ts await authClient.signIn.social({ provider: 'github', callbackURL: '/dashboard', errorCallbackURL: '/error', newUserCallbackURL: '/welcome', }); ``` ### Sign Out ```ts await authClient.signOut({ fetchOptions: { onSuccess: () => { router.push('/login'); }, }, }); ``` ## Session Management ### Client-Side Session **Using Hooks (React/Vue/Svelte/Solid):** ```tsx // React import { authClient } from "@/lib/auth-client"; export function UserProfile() { const { data: session, isPending, error } = authClient.useSession(); if (isPending) return
Loading...
; if (error) return
Error: {error.message}
; return
Welcome, {session?.user.name}!
; } // Vue // Svelte

{$session.data?.user.email}

``` **Using getSession:** ```ts const { data: session, error } = await authClient.getSession(); ``` ### Server-Side Session ```ts // Next.js import { auth } from './auth'; import { headers } from 'next/headers'; const session = await auth.api.getSession({ headers: await headers(), }); // Hono app.get('/protected', async (c) => { const session = await auth.api.getSession({ headers: c.req.raw.headers, }); if (!session) { return c.json({ error: 'Unauthorized' }, 401); } return c.json({ user: session.user }); }); ``` ## Plugin System Better Auth's plugin system allows adding advanced features easily. ### Using Plugins **Server-Side:** ```ts import { betterAuth } from 'better-auth'; import { twoFactor, organization, username } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [twoFactor(), organization(), username()], }); ``` **Client-Side:** ```ts import { createAuthClient } from 'better-auth/client'; import { twoFactorClient, organizationClient, usernameClient } from 'better-auth/client/plugins'; export const authClient = createAuthClient({ plugins: [ twoFactorClient({ twoFactorPage: '/two-factor', }), organizationClient(), usernameClient(), ], }); ``` **After Adding Plugins:** ```bash # Regenerate schema npx @better-auth/cli generate # Apply migration npx @better-auth/cli migrate ``` ### Popular Plugins #### Two-Factor Authentication (2FA) ```ts // Server import { twoFactor } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [twoFactor()], }); // Client import { twoFactorClient } from 'better-auth/client/plugins'; export const authClient = createAuthClient({ plugins: [twoFactorClient({ twoFactorPage: '/two-factor' })], }); // Usage await authClient.twoFactor.enable({ password: 'userPassword' }); await authClient.twoFactor.verifyTOTP({ code: '123456', trustDevice: true, }); ``` #### Username Authentication ```ts // Server import { username } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [username()], }); // Client import { usernameClient } from 'better-auth/client/plugins'; // Sign up with username await authClient.signUp.username({ username: 'johndoe', password: 'securePassword123', name: 'John Doe', }); ``` #### Magic Link ```ts import { magicLink } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [ magicLink({ sendMagicLink: async ({ email, url }) => { // Send email with magic link await sendEmail(email, url); }, }), ], }); ``` #### Passkey (WebAuthn) ```ts import { passkey } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [passkey()], }); // Client await authClient.passkey.register(); await authClient.passkey.signIn(); ``` #### Organization/Multi-Tenancy ```ts import { organization } from 'better-auth/plugins'; export const auth = betterAuth({ plugins: [organization()], }); // Client await authClient.organization.create({ name: 'Acme Corp', slug: 'acme', }); await authClient.organization.inviteMember({ organizationId: 'org-id', email: 'user@example.com', role: 'member', }); ``` ## Advanced Configuration ### Email Verification ```ts export const auth = betterAuth({ emailVerification: { sendVerificationEmail: async ({ user, url }) => { await sendEmail(user.email, url); }, sendOnSignUp: true, }, }); ``` ### Rate Limiting ```ts export const auth = betterAuth({ rateLimit: { enabled: true, window: 60, // seconds max: 10, // requests }, }); ``` ### Custom Session Expiration ```ts export const auth = betterAuth({ session: { expiresIn: 60 * 60 * 24 * 7, // 7 days in seconds updateAge: 60 * 60 * 24, // Update every 24 hours }, }); ``` ### CORS Configuration ```ts export const auth = betterAuth({ advanced: { corsOptions: { origin: ['https://example.com'], credentials: true, }, }, }); ``` ## Database Schema ### Core Tables Better Auth requires these core tables: - `user`: User accounts - `session`: Active sessions - `account`: OAuth provider connections - `verification`: Email verification tokens **Auto-generate with CLI:** ```bash npx @better-auth/cli generate ``` **Manual schema available in docs:** Check `/docs/concepts/database#core-schema` ## Best Practices 1. **Environment Variables**: Always use environment variables for secrets 2. **HTTPS in Production**: Set `BETTER_AUTH_URL` to HTTPS URL 3. **Session Security**: Use secure cookies in production 4. **Error Handling**: Implement proper error handling on client and server 5. **Type Safety**: Leverage TypeScript types for better DX 6. **Plugin Order**: Some plugins depend on others, check documentation 7. **Database Migrations**: Always run migrations after adding plugins 8. **Rate Limiting**: Enable rate limiting for production 9. **Email Verification**: Implement email verification for security 10. **Password Requirements**: Customize password validation as needed ## Common Patterns ### Protected Routes (Server-Side) ```ts // Next.js middleware import { auth } from '@/lib/auth'; import { NextRequest, NextResponse } from 'next/server'; export async function middleware(request: NextRequest) { const session = await auth.api.getSession({ headers: request.headers, }); if (!session) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); } export const config = { matcher: ['/dashboard/:path*'], }; ``` ### User Profile Updates ```ts await authClient.updateUser({ name: 'New Name', image: 'https://example.com/new-avatar.jpg', }); ``` ### Password Management ```ts // Change password await authClient.changePassword({ currentPassword: 'oldPassword', newPassword: 'newPassword', }); // Reset password (forgot password) await authClient.forgetPassword({ email: 'user@example.com', redirectTo: '/reset-password', }); await authClient.resetPassword({ token: 'reset-token', password: 'newPassword', }); ``` ## Troubleshooting ### Common Issues 1. **"Unable to find auth instance"** - Ensure `auth.ts` is in correct location (root, lib/, utils/) - Export auth instance as `auth` or default export 2. **Database connection errors** - Verify database credentials - Check if database server is running - Ensure correct adapter for your database 3. **CORS errors** - Configure `corsOptions` in advanced settings - Ensure client and server URLs match 4. **Plugin not working** - Run migrations after adding plugins - Check plugin is added to both server and client - Verify plugin configuration ## Framework-Specific Guides - **Next.js**: Use Next.js plugin for server actions - **Nuxt**: Configure server middleware - **SvelteKit**: Use hooks.server.ts - **Astro**: Set up API routes properly - **Hono/Express**: Use appropriate node handlers ## Resources - Documentation: https://www.better-auth.com/docs - GitHub: https://github.com/better-auth/better-auth - Plugins: https://www.better-auth.com/docs/plugins - Examples: https://www.better-auth.com/docs/examples ## Implementation Checklist When implementing Better Auth: - [ ] Install `better-auth` package - [ ] Set up environment variables (SECRET, URL) - [ ] Create auth server instance - [ ] Configure database/adapter - [ ] Run schema migration - [ ] Configure authentication methods - [ ] Mount API handler - [ ] Create client instance - [ ] Implement sign-up/sign-in UI - [ ] Add session management - [ ] Set up protected routes - [ ] Add plugins as needed - [ ] Test authentication flow - [ ] Configure email sending (if needed) - [ ] Set up error handling - [ ] Enable rate limiting for production