Prompt-to-PR:为 Next.js 应用添加 Better Auth
完整的 SOP,用于将 Better Auth 接入 Next.js App Router 项目——一次性完成会话、邮箱/密码登录、OAuth 和中间件保护。
CursorClaude CodeCodexWindsurf Next.jsTypeScriptPostgreSQL
一个完整的操作手册,用于为基于 PostgreSQL 的现有 Next.js 15 App Router 项目添加 Better Auth。涵盖身份验证服务器、路由处理器、客户端辅助函数、中间件和登录 UI,均在单次 Agent 运行中完成。
1. 需求
添加基于会话的身份验证,支持邮箱/密码登录和 GitHub OAuth。通过 Next.js 中间件保护 /dashboard 下的所有路由。使用 Better Auth 内置的 Drizzle 适配器将会话存储在现有的 PostgreSQL 数据库中。
2. 初始提示词
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. 预期的文件变更
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. 审查清单
BETTER_AUTH_SECRET至少为 32 个随机字节——绝不能硬编码。- 全匹配路由处理器同时导出
GET和POST。 src/middleware.ts使用matcher跳过_next/static、_next/image和/api/auth。- Drizzle 适配器使用与其他地方相同的
db实例——不创建第二个连接。 auth-client.ts中的createAuthClient()指向正确的baseURL(读取NEXT_PUBLIC_APP_URL)。- 登录页面为客户端组件(
"use client")——不导入仅服务端的模块。 - GitHub OAuth 回调 URL 在 GitHub 应用设置中与
/api/auth/callback/github匹配。 - 新增的模式表是在现有表的基础上添加,而非替换。
5. 测试命令
# Generate and run the new auth migrationsnpx drizzle-kit generatenpx drizzle-kit migrate
# Start dev serverbun dev
# Smoke-test: attempt to hit protected route without a sessioncurl -I http://localhost:3000/dashboard# Expect: 307 redirect to /sign-in
# Run any existing test suitebun test6. 常见故障
- 运行时
BETTER_AUTH_SECRET缺失——Better Auth 在启动时抛出错误。将其添加到.env.local;在auth.ts中使用console.log(process.env.BETTER_AUTH_SECRET?.length)确认(之后删除)。 - 重复的 Drizzle 连接——Agent 在
auth.ts内部创建了第二个drizzle()调用,而不是从src/db/index.ts导入。导致两个连接池。 - 中间件匹配
/api/auth——导致无限重定向循环。matcher必须排除/api/auth/(.*)。 - 客户端组件导入仅服务端的
auth——构建错误。只有auth-client.ts应在客户端组件中导入。 - GitHub 回调 URL 不匹配——OAuth 静默失败。确认 GitHub OAuth 应用回调在开发环境下为
http://localhost:3000/api/auth/callback/github。
7. 修复提示词
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 thancreating a second Drizzle instance.8. PR 描述
## 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`