# Prompt-to-PR : Ajouter Better Auth à une application Next.js

> SOP complet pour intégrer Better Auth dans un projet Next.js App Router — sessions, email/mot de passe, OAuth et protection middleware en une seule passe.

**Type:** Playbook  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** Next.js, TypeScript, PostgreSQL  
**Difficulty:** medium  
**Updated:** 2026-06-08

---

Un guide complet pour ajouter [Better Auth](https://www.better-auth.com/) à un projet Next.js 15 App Router existant utilisant PostgreSQL. Couvre le serveur d'authentification, le gestionnaire de routes, l'aide client, le middleware et l'interface de connexion en une seule exécution d'agent.

## 1. Exigence

Ajoutez une authentification basée sur les sessions avec email/mot de passe et OAuth GitHub. Protégez toutes les routes sous `/dashboard` via le middleware Next.js. Stockez les sessions dans la base de données PostgreSQL existante en utilisant l'adaptateur Drizzle intégré de Better Auth.

## 2. Première invite

```txt title="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. Modifications de fichiers attendues

```txt
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. Liste de vérification

- `BETTER_AUTH_SECRET` fait au moins 32 octets aléatoires — jamais codé en dur.
- Le gestionnaire de route universel exporte à la fois `GET` et `POST`.
- `src/middleware.ts` utilise `matcher` pour ignorer `_next/static`, `_next/image` et `/api/auth`.
- L'adaptateur Drizzle reçoit la même instance `db` utilisée ailleurs — pas de seconde connexion.
- `createAuthClient()` dans `auth-client.ts` pointe vers le bon `baseURL` (lit `NEXT_PUBLIC_APP_URL`).
- La page de connexion est un composant client (`"use client"`) — pas d'imports réservés au serveur.
- L'URL de rappel OAuth GitHub dans les paramètres de l'application GitHub correspond à `/api/auth/callback/github`.
- Les nouvelles tables de schéma sont ajoutées, ne remplaçant pas les tables existantes.

## 5. Commandes de test

```bash
# 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. Échecs courants

- **`BETTER_AUTH_SECRET` manquant à l'exécution** — Better Auth lève une erreur au démarrage. Ajoutez-le dans `.env.local` ; confirmez avec `console.log(process.env.BETTER_AUTH_SECRET?.length)` dans `auth.ts` (supprimez ensuite).
- **Double connexion Drizzle** — l'agent crée un second appel `drizzle()` dans `auth.ts` au lieu d'importer depuis `src/db/index.ts`. Provoque deux pools de connexions.
- **Le middleware correspond à `/api/auth`** — provoque une boucle de redirection infinie. Le `matcher` doit exclure `/api/auth/(.*)`.
- **Le composant client importe `auth` réservé au serveur** — erreur de build. Seul `auth-client.ts` doit être importé dans les composants clients.
- **Non-correspondance de l'URL de rappel GitHub** — OAuth échoue silencieusement. Confirmez que le rappel de l'application OAuth GitHub est `http://localhost:3000/api/auth/callback/github` en développement.

## 7. Invite de correction

```txt title="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. Description de la PR

```md title="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`
```