Claude Code Plugins

Community-maintained marketplace

Feedback
1
0

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.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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

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:

BETTER_AUTH_SECRET=<generated-secret-key>
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/:

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:

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:

// Drizzle
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/db";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "pg", // or "mysql", "sqlite"
  }),
});

// 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",
  }),
});

// 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:

# 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):

// 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:

// server/api/auth/[...all].ts
import { auth } from "~/utils/auth";

export default defineEventHandler((event) => {
  return auth.handler(toWebRequest(event));
});

SvelteKit:

// 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:

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:

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:

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:

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    autoSignIn: true, // default: true
  }
});

Client Usage:

// 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:

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:

await authClient.signIn.social({
  provider: "github",
  callbackURL: "/dashboard",
  errorCallbackURL: "/error",
  newUserCallbackURL: "/welcome",
});

Sign Out

await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/login");
    }
  }
});

Session Management

Client-Side Session

Using Hooks (React/Vue/Svelte/Solid):

// React
import { authClient } from "@/lib/auth-client";

export function UserProfile() {
  const { data: session, isPending, error } = authClient.useSession();

  if (isPending) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return <div>Welcome, {session?.user.name}!</div>;
}

// Vue
<script setup>
import { authClient } from "~/lib/auth-client";
const session = authClient.useSession();
</script>

<template>
  <div v-if="session.data">{{ session.data.user.email }}</div>
</template>

// Svelte
<script>
import { authClient } from "$lib/auth-client";
const session = authClient.useSession();
</script>

<p>{$session.data?.user.email}</p>

Using getSession:

const { data: session, error } = await authClient.getSession();

Server-Side Session

// 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:

import { betterAuth } from "better-auth";
import { twoFactor, organization, username } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    twoFactor(),
    organization(),
    username(),
  ]
});

Client-Side:

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:

# Regenerate schema
npx @better-auth/cli generate

# Apply migration
npx @better-auth/cli migrate

Popular Plugins

Two-Factor Authentication (2FA)

// 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

// 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

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)

import { passkey } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [passkey()]
});

// Client
await authClient.passkey.register();
await authClient.passkey.signIn();

Organization/Multi-Tenancy

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

export const auth = betterAuth({
  emailVerification: {
    sendVerificationEmail: async ({ user, url }) => {
      await sendEmail(user.email, url);
    },
    sendOnSignUp: true
  }
});

Rate Limiting

export const auth = betterAuth({
  rateLimit: {
    enabled: true,
    window: 60, // seconds
    max: 10 // requests
  }
});

Custom Session Expiration

export const auth = betterAuth({
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days in seconds
    updateAge: 60 * 60 * 24 // Update every 24 hours
  }
});

CORS Configuration

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:

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)

// 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

await authClient.updateUser({
  name: "New Name",
  image: "https://example.com/new-avatar.jpg"
});

Password Management

// 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

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