P PasteCode
Guía de trabajo

Prompt-to-PR: Agregar Better Auth a una App de Next.js

SOP completo para integrar Better Auth en un proyecto Next.js App Router — sesiones, correo/contraseña, OAuth y protección de middleware en un solo paso.

CursorClaude CodeCodexWindsurf Next.jsTypeScriptPostgreSQL
.md .json Dificultad: Medio Actualizado 8 jun 2026

Un manual completo para agregar Better Auth a un proyecto existente de Next.js 15 App Router respaldado por PostgreSQL. Abarca el servidor de autenticación, el manejador de rutas, el ayudante del cliente, el middleware y la interfaz de inicio de sesión en una sola ejecución del agente.

1. Requisito

Agregar autenticación basada en sesiones con correo/contraseña y OAuth de GitHub. Proteger todas las rutas bajo /dashboard mediante el middleware de Next.js. Almacenar sesiones en la base de datos PostgreSQL existente usando el adaptador Drizzle integrado de Better Auth.

2. Primer Prompt

First Prompt
Add Better Auth to this Next.js 15 App Router project.
Stack: PostgreSQL (Drizzle ORM, schema in src/db/schema.ts), TypeScript, Tailwind.
Tasks:
1. Install `better-auth` and `@better-auth/drizzle`.
2. Create `src/lib/auth.ts` — configure BetterAuth with the Drizzle adapter,
emailAndPassword plugin, and GitHub socialProvider. Read secrets from
BETTER_AUTH_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET env vars.
3. Create `src/app/api/auth/[...all]/route.ts` that re-exports the auth handler
for GET and POST.
4. Create `src/lib/auth-client.ts` that exports a `createAuthClient()` instance
for client components.
5. Add Better Auth tables to `src/db/schema.ts` using `auth.api.generateSchema()`.
6. Create `src/middleware.ts` that protects every route under `/dashboard`;
redirect unauthenticated requests to `/sign-in`.
7. Create `src/app/(auth)/sign-in/page.tsx` — a minimal email/password form and
a "Continue with GitHub" button using the auth client.
8. Do not touch any existing route or component unless strictly necessary.

3. Cambios esperados en archivos

package.json (better-auth, @better-auth/drizzle)
src/lib/auth.ts (new — server auth instance)
src/lib/auth-client.ts (new — browser auth client)
src/app/api/auth/[...all]/route.ts (new — catch-all route handler)
src/db/schema.ts (new tables: user, session, account, verification)
src/middleware.ts (new — route protection)
src/app/(auth)/sign-in/page.tsx (new — sign-in UI)
.env.local.example (BETTER_AUTH_SECRET, GITHUB_* vars)

4. Lista de verificación

  • BETTER_AUTH_SECRET tiene al menos 32 bytes aleatorios — nunca codificado.
  • El manejador de ruta comodín exporta tanto GET como POST.
  • src/middleware.ts usa matcher para omitir _next/static, _next/image y /api/auth.
  • El adaptador Drizzle recibe la misma instancia de db utilizada en otros lugares — sin segunda conexión.
  • createAuthClient() en auth-client.ts apunta al baseURL correcto (lee NEXT_PUBLIC_APP_URL).
  • La página de inicio de sesión es un Componente Cliente ("use client") — sin importaciones solo de servidor.
  • La URL de devolución de llamada de OAuth de GitHub en la configuración de la app de GitHub coincide con /api/auth/callback/github.
  • Se agregan nuevas tablas de esquema, no se reemplazan las existentes.

5. Comandos de prueba

Terminal window
# Generate and run the new auth migrations
npx drizzle-kit generate
npx drizzle-kit migrate
# Start dev server
bun dev
# Smoke-test: attempt to hit protected route without a session
curl -I http://localhost:3000/dashboard
# Expect: 307 redirect to /sign-in
# Run any existing test suite
bun test

6. Fallos comunes

  • BETTER_AUTH_SECRET faltante en tiempo de ejecución — Better Auth arroja un error al inicio. Agrégalo a .env.local; confirma con console.log(process.env.BETTER_AUTH_SECRET?.length) en auth.ts (elimina después).
  • Conexión Drizzle duplicada — el agente crea una segunda llamada drizzle() dentro de auth.ts en lugar de importar desde src/db/index.ts. Causa dos grupos de conexiones.
  • Middleware coincide con /api/auth — causa un bucle infinito de redirección. El matcher debe excluir /api/auth/(.*).
  • Componente cliente importa auth solo de servidor — error de compilación. Solo auth-client.ts debe importarse en Componentes Cliente.
  • Discrepancia en la URL de devolución de GitHub — OAuth falla silenciosamente. Confirma que la devolución de la app OAuth de GitHub es http://localhost:3000/api/auth/callback/github en desarrollo.

7. Prompt de corrección

Fix Prompt
The middleware is redirecting /api/auth/* to /sign-in, causing an infinite loop.
Fix src/middleware.ts so the matcher explicitly excludes:
- /api/auth/:path*
- /_next/static/:path*
- /_next/image
- /favicon.ico
Also confirm that auth.ts imports `db` from `src/db/index.ts` rather than
creating a second Drizzle instance.

8. Descripción del PR

PR description
## Auth: Add Better Auth (email/password + GitHub OAuth)
- Installs `better-auth` with Drizzle adapter against the existing PostgreSQL db
- Catch-all `/api/auth/[...all]` route handles all auth requests
- Middleware protects `/dashboard/**`; unauthenticated → `/sign-in`
- New sign-in page with email/password form and GitHub OAuth button
- Four new schema tables (`user`, `session`, `account`, `verification`) via migration
**Env vars required** (see `.env.local.example`):
- `BETTER_AUTH_SECRET` — min 32-byte random string
- `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET`
- `NEXT_PUBLIC_APP_URL`