--- description: Interactive authentication setup wizard. Configures better-auth, OAuth providers, and generates handlers for Cloudflare Workers. --- # Authentication Setup Command Guide developers through authentication stack configuration with automated code generation, database migrations, and MCP-driven provider setup. ## Introduction Senior Security Engineer with expertise in authentication, better-auth, and Cloudflare Workers security **This command will**: - Detect framework (Tanstack Start vs standalone Worker) - Configure better-auth for all authentication needs - Query better-auth MCP for OAuth provider requirements - Generate login/register/logout handlers with React Server Functions - Create D1 database schema for users/sessions - Configure session security (HTTPS cookies, CSRF) - Generate environment variables template ## Prerequisites - Cloudflare Workers project (Tanstack Start or Hono) - D1 database configured (or will create) - For OAuth: Provider credentials (Google, GitHub, etc.) ## Main Tasks ### 1. Detect Framework & Auth Requirements **Ask User**: ```markdown 🔐 Authentication Setup Wizard 1. What framework are you using? a) Tanstack Start b) Standalone Worker (Hono/plain TS) 2. What authentication methods do you need? a) Email/Password only b) OAuth providers (Google, GitHub, etc.) c) Passkeys d) Magic Links e) Multiple (OAuth + Email/Password) ``` **Decision Logic**: ``` If Tanstack Start: → better-auth with React Server Functions If Standalone Worker (Hono): → better-auth with Hono middleware ``` ### 2. Install Dependencies **For Tanstack Start**: ```bash pnpm add better-auth @node-rs/argon2 ``` **For Standalone Worker (Hono)**: ```bash pnpm add better-auth hono @node-rs/argon2 ``` ### 3. Generate Configuration Files #### Tanstack Start + better-auth **Generate**: `app/auth.server.ts` ```typescript import { betterAuth } from 'better-auth'; export const auth = betterAuth({ database: { type: 'd1', database: process.env.DB, }, emailAndPassword: { enabled: true, requireEmailVerification: true, }, session: { cookieName: 'session', maxAge: 60 * 60 * 24 * 7, // 7 days cookieCache: { enabled: true, maxAge: 5 * 60 * 1000, // 5 minutes }, }, }); ``` **Generate**: `server/api/auth/login.post.ts` ```typescript import { hash, verify } from '@node-rs/argon2'; export default defineEventHandler(async (event) => { const { email, password } = await readBody(event); const user = await event.context.cloudflare.env.DB.prepare( 'SELECT id, email, password_hash FROM users WHERE email = ?' ).bind(email).first(); if (!user || !await verify(user.password_hash, password)) { throw createError({ statusCode: 401, message: 'Invalid credentials' }); } await setUserSession(event, { user: { id: user.id, email: user.email }, loggedInAt: new Date().toISOString(), }); return { success: true }; }); ``` **Query MCP for OAuth Setup**: ```typescript const googleSetup = await mcp.betterAuth.getProviderSetup('google'); const githubSetup = await mcp.betterAuth.getProviderSetup('github'); ``` **Generate**: `server/utils/auth.ts` ```typescript import { betterAuth } from 'better-auth'; export const auth = betterAuth({ database: { type: 'd1', database: process.env.DB, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }, github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, }, }, }); ``` **Generate**: `server/api/auth/[...].ts` (OAuth handler) ```typescript export default defineEventHandler(async (event) => { const response = await auth.handler(event.node.req, event.node.res); // if (event.node.req.url?.includes('/callback')) { const session = await auth.api.getSession({ headers: event.node.req.headers }); if (session) { await setUserSession(event, { user: { id: session.user.id, email: session.user.email, name: session.user.name, provider: session.user.provider, }, }); } } return response; }); ``` ### 4. Generate Database Migration **Generate**: `migrations/0001_auth.sql` ```sql -- Users table CREATE TABLE users ( id TEXT PRIMARY KEY, email TEXT UNIQUE NOT NULL, email_verified INTEGER DEFAULT 0, password_hash TEXT, -- NULL for OAuth-only name TEXT, image TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); -- OAuth accounts (if using better-auth) CREATE TABLE accounts ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, provider TEXT NOT NULL, provider_account_id TEXT NOT NULL, access_token TEXT, refresh_token TEXT, expires_at INTEGER, created_at TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, UNIQUE(provider, provider_account_id) ); CREATE INDEX idx_users_email ON users(email); CREATE INDEX idx_accounts_user ON accounts(user_id); ``` ### 5. Configure Environment Variables **Generate**: `.dev.vars` ```bash # better-auth secret (generate with: openssl rand -base64 32) BETTER_AUTH_SECRET=your-32-char-secret-here # OAuth credentials (if using OAuth providers) GOOGLE_CLIENT_ID=your-google-client-id GOOGLE_CLIENT_SECRET=your-google-client-secret GITHUB_CLIENT_ID=your-github-client-id GITHUB_CLIENT_SECRET=your-github-client-secret ``` **Production Setup**: ```bash wrangler secret put BETTER_AUTH_SECRET wrangler secret put GOOGLE_CLIENT_SECRET wrangler secret put GITHUB_CLIENT_SECRET ``` ### 6. Generate Protected Route Example **Generate**: `server/api/protected.get.ts` ```typescript export default defineEventHandler(async (event) => { const session = await requireUserSession(event); return { message: 'Protected data', user: session.user, }; }); ``` ### 7. Validate Setup **Security Checklist**: - ✅ HTTPS-only cookies configured - ✅ httpOnly flag set - ✅ SameSite configured (lax or strict) - ✅ Password hashing uses Argon2id - ✅ Session password is 32+ characters - ✅ OAuth redirect URIs configured (if applicable) - ✅ CSRF protection enabled (automatic) ## Success Criteria ✅ Auth setup complete when: - Framework detected and appropriate stack chosen - Dependencies installed - Configuration files generated - Database migration created - Environment variables template created - Security settings validated - Example handlers provided ## Output Summary **Files Created**: - Configuration (app.config.ts or auth.ts) - Auth handlers (login, register, logout, OAuth callback) - Database migration (users, accounts) - Protected route example - Environment variables template **Next Actions**: 1. Run database migration 2. Generate session password (32+ chars) 3. Configure OAuth providers (if applicable) 4. Test authentication flow 5. Add rate limiting to auth endpoints 6. Deploy with `/es-deploy` ## Notes - Always use better-auth for authentication (Workers-optimized) - Add OAuth/passkeys/magic links as needed - Query better-auth MCP for latest provider requirements - Use Argon2id for password hashing (never bcrypt) - Store secrets in Cloudflare Workers secrets (not wrangler.toml) - See `agents/integrations/better-auth-specialist` for detailed guidance