create-auth-skill
Skill for creating auth layers in TypeScript/JavaScript apps using Better Auth.
npxskills add better-auth/skills--skill create-auth-skillLoading…
Skill for creating auth layers in TypeScript/JavaScript apps using Better Auth.
npxskills add better-auth/skills--skill create-auth-skillLoading…
Guide for adding authentication to TypeScript/JavaScript applications using Better Auth.
For code examples and syntax, see better-auth.com/docs.
Before writing any code, gather requirements by scanning the project and asking the user structured questions. This ensures the implementation matches their needs.
Analyze the codebase to auto-detect:
next.config, svelte.config, nuxt.config, astro.config, vite.config, or Express/Hono entry files.prisma/schema.prisma, drizzle.config.ts, package.json deps (pg, postgres, @neondatabase/serverless, mysql2, better-sqlite3, mongoose, mongodb). If drizzle.config.ts exists, read its dialect field to determine the DB type (e.g., "postgresql" → Drizzle + Postgres). Also check which Drizzle driver is installed (drizzle-orm/node-postgres → pg, drizzle-orm/postgres-js → postgres, drizzle-orm/neon-http → Neon).next-auth, lucia, clerk, supabase/auth, firebase/auth) in package.json or imports.pnpm-lock.yaml, yarn.lock, bun.lockb, or package-lock.json.Use what you find to pre-fill defaults and skip questions you can already answer.
Use the AskQuestion tool to ask the user all applicable questions in a single call. Skip any question you already have a confident answer for from the scan. Group them under a title like "Auth Setup Planning".
Questions to ask:
Project type (skip if detected)
Framework (skip if detected)
Database & ORM (skip if detected)
Authentication methods (always ask, allow multiple)
allow_multiple: trueSocial providers (only if they selected Social OAuth above — ask in a follow-up call)
allow_multiple: trueAfter collecting answers, present a concise implementation plan as a markdown checklist. Example:
## Auth Implementation Plan
- **Framework:** Next.js (App Router)
- **Database:** PostgreSQL via Prisma
- **Auth methods:** Email/password, Google OAuth, GitHub OAuth
- **Plugins:** 2FA, Organizations, Email verification
- **UI:** Custom forms
### Steps
1. Install `better-auth` and `@better-auth/cli`
2. Create `lib/auth.ts` with server config
3. Create `lib/auth-client.ts` with React client
4. Set up route handler at `app/api/auth/[...all]/route.ts`
5. Configure Prisma adapter and generate schema
6. Add Google & GitHub OAuth providers
7. Enable `twoFactor` and `organization` plugins
8. Set up email verification handler
9. Run migrations
10. Create sign-in / sign-up pages
Ask the user to confirm the plan before proceeding to Phase 2.
Only proceed here after the user confirms the plan from Phase 1.
Follow the decision tree below, guided by the answers collected above.
Is this a new/empty project?
├─ YES → New project setup
│ 1. Install better-auth (+ scoped packages per plan)
│ 2. Create auth.ts with all planned config
│ 3. Create auth-client.ts with framework client
│ 4. Set up route handler
│ 5. Set up environment variables
│ 6. Run CLI migrate/generate
│ 7. Add plugins from plan
│ 8. Create auth UI pages
│
├─ MIGRATING → Migration from existing auth
│ 1. Audit current auth for gaps
│ 2. Plan incremental migration
│ 3. Install better-auth alongside existing auth
│ 4. Migrate routes, then session logic, then UI
│ 5. Remove old auth library
│ 6. See migration guides in docs
│
└─ ADDING → Add auth to existing project
1. Analyze project structure
2. Install better-auth
3. Create auth config matching plan
4. Add route handler
5. Run schema migrations
6. Integrate into existing pages
7. Add planned plugins and features
At the end of implementation, guide users thoroughly on remaining next steps (e.g., setting up OAuth app credentials, deploying env vars, testing flows).
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 |
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.
Location: lib/auth.ts or src/lib/auth.ts
Minimal config needs:
database - Connection or adapteremailAndPassword: { enabled: true } - For email/password authStandard config adds:
socialProviders - OAuth providers (google, github, etc.)emailVerification.sendVerificationEmail - Email verification handleremailAndPassword.sendResetPassword - Password reset handlerFull config adds:
plugins - Array of feature pluginssession - Expiry, cookie cache settingsaccount.accountLinking - Multi-provider linkingrateLimit - Rate limiting configExport types: export type Session = typeof auth.$Infer.Session
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
| 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 |
Next.js Server Components: Add nextCookies() plugin to auth config.
| 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 (dev) | npx @better-auth/cli@latest generate --output src/db/auth-schema.ts then npx drizzle-kit push |
| Drizzle (prod) | npx @better-auth/cli@latest generate --output src/db/auth-schema.ts then npx drizzle-kit generate then |
Note:
drizzle-kit pushskips migration files and is only safe for development. Usedrizzle-kit generate+drizzle-kit migratein production.
Re-run after adding plugins.
| 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 (pg) | drizzleAdapter(db, { provider: "pg" }) from |
Before using drizzleAdapter, initialize the db instance:
// Option 1: node-postgres (pg)
import { drizzle } from "drizzle-orm/node-postgres"
import { Pool } from "pg"
import * as schema from "./auth-schema"
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
export const db = drizzle(pool, { schema })
// Option 2: postgres.js
import { drizzle } from "drizzle-orm/postgres-js"
import postgres from "postgres"
import * as schema from "./auth-schema"
const client = postgres(process.env.DATABASE_URL!)
export const db = drizzle(client, { schema })
// Option 3: Neon serverless
import { drizzle } from "drizzle-orm/neon-http"
import { neon } from "@neondatabase/serverless"
import * as schema from "./auth-schema"
const sql = neon(process.env.DATABASE_URL!)
export const db = drizzle(sql, { schema })
Then pass to Better Auth:
import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { db } from "./db"
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "pg" }),
// ...
})
drizzle.config.ts)Required for drizzle-kit commands to find your schema:
import { defineConfig } from "drizzle-kit"
export default defineConfig({
schema: "./src/db/auth-schema.ts",
out: "./drizzle",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
})
| Plugin | Server Import | Client Import | Purpose |
|---|---|---|---|
twoFactor | better-auth/plugins | twoFactorClient | 2FA with TOTP/OTP |
organization | better-auth/plugins | organizationClient | Teams/orgs |
admin |
Plugin pattern: Server plugin + client plugin + run migrations.
Sign in flow:
signIn.email({ email, password }) or signIn.social({ provider, callbackURL })error in responseSession 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.
BETTER_AUTH_SECRET set (32+ chars)advanced.useSecureCookies: true in productiontrustedOrigins configuredaccount.accountLinking reviewed| 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 |
Email verification (only if Email & password was selected above — ask in a follow-up call)
Email provider (only if email verification is Yes, or if Password reset is selected in features — ask in a follow-up call)
Features & plugins (always ask, allow multiple)
allow_multiple: trueAuth pages (always ask, allow multiple — pre-select based on earlier answers)
allow_multiple: trueAuth UI style (always ask)
svelteKitHandler(auth) |
| SolidStart | Route file | solidStartHandler(auth) |
| Hono | Route file | auth.handler(c.req.raw) |
npx drizzle-kit migratebetter-auth/adapters/drizzle| Drizzle (mysql) | drizzleAdapter(db, { provider: "mysql" }) from better-auth/adapters/drizzle |
| Drizzle (sqlite) | drizzleAdapter(db, { provider: "sqlite" }) from better-auth/adapters/drizzle |
| MongoDB | mongodbAdapter(db) from better-auth/adapters/mongodb |
better-auth/pluginsadminClient |
| 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 |
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
CLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.
CLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).