create-auth-skill

$npx skills add better-auth/skills --skill create-auth-skill
SKILL.md

Create Auth Skill

Guide for adding authentication to TypeScript/JavaScript applications using Better Auth. **For code examples and syntax, see [better-auth.com/docs](https://better-auth.com/docs).** * * *

Create Auth Skill

Guide for adding authentication to TypeScript/JavaScript applications using Better Auth.
For code examples and syntax, see better-auth.com/docs.

Decision Tree

Is this a new/empty project?
├─ YES → New project setup
│   1. Identify framework
│   2. Choose database
│   3. Install better-auth
│   4. Create auth.ts + auth-client.ts
│   5. Set up route handler
│   6. Run CLI migrate/generate
│   7. Add features via plugins
│
└─ NO → Does project have existing auth?
    ├─ YES → Migration/enhancement
    │   • Audit current auth for gaps
    │   • Plan incremental migration
    │   • See migration guides in docs
    │
    └─ NO → Add auth to existing project
        1. Analyze project structure
        2. Install better-auth
        3. Create auth config
        4. Add route handler
        5. Run schema migrations
        6. Integrate into existing pages

Installation

Core: npm install better-auth
Scoped packages (as needed):
Package
Use case
@better-auth/passkey
WebAuthn/Passkey auth
@better-auth/sso
SAML/OIDC enterprise SSO
@better-auth/stripe
Stripe payments
@better-auth/scim
SCIM user provisioning
@better-auth/expo
React Native/Expo

Environment Variables

BETTER_AUTH_SECRET=<32+ chars, generate with: openssl rand -base64 32>
BETTER_AUTH_URL=http://localhost:3000
DATABASE_URL=<your database connection string>
Add OAuth secrets as needed: GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GOOGLE_CLIENT_ID, etc.

Server Config (auth.ts)

Location: lib/auth.ts or src/lib/auth.ts
Minimal config needs:
  • database - Connection or adapter
  • emailAndPassword: { enabled: true } - For email/password auth
Standard config adds:
  • socialProviders - OAuth providers (google, github, etc.)
  • emailVerification.sendVerificationEmail - Email verification handler
  • emailAndPassword.sendResetPassword - Password reset handler
Full config adds:
  • plugins - Array of feature plugins
  • session - Expiry, cookie cache settings
  • account.accountLinking - Multi-provider linking
  • rateLimit - Rate limiting config
Export types: export type Session = typeof auth.$Infer.Session

Client Config (auth-client.ts)

Import by framework:
Framework
Import
React/Next.js
better-auth/react
Vue
better-auth/vue
Svelte
better-auth/svelte
Solid
better-auth/solid
Vanilla JS
better-auth/client
Client plugins go in createAuthClient({ plugins: [...] }).
Common exports: signIn, signUp, signOut, useSession, getSession

Route Handler Setup

Framework
File
Handler
Next.js App Router
app/api/auth/[...all]/route.ts
toNextJsHandler(auth) → export { GET, POST }
Next.js Pages
pages/api/auth/[...all].ts
toNextJsHandler(auth) → default export
Express
Any file
app.all("/api/auth/*", toNodeHandler(auth))
SvelteKit
src/hooks.server.ts
svelteKitHandler(auth)
SolidStart
Route file
solidStartHandler(auth)
Hono
Route file
auth.handler(c.req.raw)
Next.js Server Components: Add nextCookies() plugin to auth config.

Database Migrations

Adapter
Command
Built-in Kysely
npx @better-auth/cli@latest migrate (applies directly)
Prisma
npx @better-auth/cli@latest generate --output prisma/schema.prisma then npx prisma migrate dev
Drizzle
npx @better-auth/cli@latest generate --output src/db/auth-schema.ts then npx drizzle-kit push
Re-run after adding plugins.

Database Adapters

Database
Setup
SQLite
Pass better-sqlite3 or bun:sqlite instance directly
PostgreSQL
Pass pg.Pool instance directly
MySQL
Pass mysql2 pool directly
Prisma
prismaAdapter(prisma, { provider: "postgresql" }) from better-auth/adapters/prisma
Drizzle
drizzleAdapter(db, { provider: "pg" }) from better-auth/adapters/drizzle
MongoDB
mongodbAdapter(db) from better-auth/adapters/mongodb

Common Plugins

Plugin
Server Import
Client Import
Purpose
twoFactor
better-auth/plugins
twoFactorClient
2FA with TOTP/OTP
organization
better-auth/plugins
organizationClient
Teams/orgs
admin
better-auth/plugins
adminClient
User management
bearer
better-auth/plugins
-
API token auth
openAPI
better-auth/plugins
-
API docs
passkey
@better-auth/passkey
passkeyClient
WebAuthn
sso
@better-auth/sso
-
Enterprise SSO
Plugin pattern: Server plugin + client plugin + run migrations.

Auth UI Implementation

Sign in flow:
  1. signIn.email({ email, password }) or signIn.social({ provider, callbackURL })
  2. Handle error in response
  3. Redirect on success
Session check (client): useSession() hook returns { data: session, isPending }
Session check (server): auth.api.getSession({ headers: await headers() })
Protected routes: Check session, redirect to /sign-in if null.

Security Checklist

  • BETTER_AUTH_SECRET set (32+ chars)
  • advanced.useSecureCookies: true in production
  • trustedOrigins configured
  • Rate limits enabled
  • Email verification enabled
  • Password reset implemented
  • 2FA for sensitive apps
  • CSRF protection NOT disabled
  • account.accountLinking reviewed

Troubleshooting

Issue
Fix
"Secret not set"
Add BETTER_AUTH_SECRET env var
"Invalid Origin"
Add domain to trustedOrigins
Cookies not setting
Check baseURL matches domain; enable secure cookies in prod
OAuth callback errors
Verify redirect URIs in provider dashboard
Type errors after adding plugin
Re-run CLI generate/migrate

Resources