Configuration D1 + KV pour Better Auth Cloudflare
Objet : Spécification configuration Cloudflare D1 et KV pour Better Auth
Type : Documentation Technique (DAT)
Couche : Couche 03 (Backend - Cloudflare)
Emplacement :apps/web/wrangler.toml+ configuration Better Auth
Statut : DOC (Proposé)
1. Vue dâensemble (DOC)
Section titled â1. Vue dâensemble (DOC)â1.1. Description
Section titled â1.1. DescriptionâConfiguration dĂ©taillĂ©e des ressources Cloudflare D1 et KV nĂ©cessaires pour Better Auth Cloudflare, incluant la crĂ©ation des bases de donnĂ©es, les bindings wrangler.jsonc (conformĂ©ment aux recommandations Cloudflare), lâobservabilitĂ© activĂ©e, et la configuration de Better Auth.
1.2. Objectif
Section titled â1.2. Objectifâ- DĂ©finir lâarchitecture de stockage D1 + KV
- Spécifier la configuration wrangler.jsonc avec observabilité
- Documenter la création des ressources Cloudflare via script bash
- Configurer Better Auth avec D1 et KV
2. Architecture de Stockage (CODE)
Section titled â2. Architecture de Stockage (CODE)â2.1. Ressources Cloudflare
Section titled â2.1. Ressources CloudflareâD1 Database : amn-auth-db
- Stockage principal des utilisateurs et sessions
- Schéma géré par Drizzle ORM
- Migrations automatiques via CLI Better Auth
- Source de vĂ©ritĂ© pour les donnĂ©es dâauthentification
KV Namespace : AUTH_SESSIONS_KV (existant)
- Cache des sessions : Pour Ă©viter de requĂȘter D1 Ă chaque vĂ©rification de session (ce qui consommerait votre quota dâĂ©criture/lecture D1)
- Amélioration des performances : Lecture KV plus rapide que D1 (edge cache)
- Optimisation des coĂ»ts : RĂ©duction des requĂȘtes D1 (quota limitĂ©)
- Fallback : Disponibilité en cas de panne D1
2.2. Flux de Vérification de Session avec KV
Section titled â2.2. Flux de VĂ©rification de Session avec KVâRequĂȘte de vĂ©rification session â ⌠[Lire KV] â ââââââŽâââââ â â ⌠âŒ[Hit KV] [Miss KV] â â â ⌠â [Lire D1] â â â ⌠â [Ăcrire KV] â â ââââââŹâââââ â ⌠[Retour session]Avantages de ce flux :
- PremiĂšre requĂȘte : Lecture D1 + Ă©criture KV (coĂ»t D1)
- RequĂȘtes suivantes : Lecture KV uniquement (coĂ»t rĂ©duit)
- Performance : KV est edge-cached, plus rapide que D1
- Coût : KV lectures sont moins chÚres que D1 lectures
- Scalabilité : KV gÚre mieux les pics de traffic
2.2. Schéma D1 (Géré par Better Auth)
Section titled â2.2. SchĂ©ma D1 (GĂ©rĂ© par Better Auth)âBetter Auth gĂ©nĂšre automatiquement le schĂ©ma suivant via Drizzle :
-- Table: userCREATE TABLE user ( id TEXT PRIMARY KEY, email TEXT UNIQUE NOT NULL, emailVerified INTEGER DEFAULT 0, name TEXT, image TEXT, createdAt INTEGER NOT NULL, updatedAt INTEGER NOT NULL);
-- Table: sessionCREATE TABLE session ( id TEXT PRIMARY KEY, userId TEXT NOT NULL, expiresAt INTEGER NOT NULL, token TEXT UNIQUE NOT NULL, ipAddress TEXT, userAgent TEXT, createdAt INTEGER NOT NULL, updatedAt INTEGER NOT NULL, FOREIGN KEY (userId) REFERENCES user(id) ON DELETE CASCADE);
-- Table: account (pour OAuth providers)CREATE TABLE account ( id TEXT PRIMARY KEY, userId TEXT NOT NULL, accountId TEXT NOT NULL, providerId TEXT NOT NULL, accessToken TEXT, refreshToken TEXT, idToken TEXT, expiresAt INTEGER, password TEXT, createdAt INTEGER NOT NULL, updatedAt INTEGER NOT NULL, FOREIGN KEY (userId) REFERENCES user(id) ON DELETE CASCADE);
-- Table: verification (pour email verification)CREATE TABLE verification ( id TEXT PRIMARY KEY, identifier TEXT NOT NULL, value TEXT NOT NULL, expiresAt INTEGER NOT NULL, createdAt INTEGER NOT NULL, updatedAt INTEGER NOT NULL);3. Configuration Wrangler (CODE)
Section titled â3. Configuration Wrangler (CODE)â3.1. apps/web/wrangler.jsonc
Section titled â3.1. apps/web/wrangler.jsoncâConformĂ©ment aux recommandations Cloudflare, nous utilisons wrangler.jsonc au lieu de wrangler.toml avec observabilitĂ© activĂ©e.
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "amn-dev", "compatibility_date": "2026-09-01", "compatibility_flags": ["nodejs_compat"],
"observability": { "enabled": true, "logs": { "head_sampling_rate": 1 }, "traces": { "enabled": true, "head_sampling_rate": 0.01 } },
"d1_databases": [ { "binding": "AUTH_DB", "database_name": "amn-auth-db", "database_id": "<your-d1-database-id>", "migrations_dir": "drizzle" } ],
"kv_namespaces": [ { "binding": "AUTH_KV", "id": "4a990eb34db9430284b0961ac5d107dd" } ],
"services": [ { "binding": "FORM_HANDLER", "service": "amn-form-handler-dev" } ],
"env": { "dev": { "name": "amn-dev", "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 }, "traces": { "enabled": true, "head_sampling_rate": 0.01 } }, "d1_databases": [ { "binding": "AUTH_DB", "database_name": "amn-auth-db", "database_id": "<your-d1-database-id>", "migrations_dir": "drizzle" } ], "kv_namespaces": [ { "binding": "AUTH_KV", "id": "4a990eb34db9430284b0961ac5d107dd" } ], "services": [ { "binding": "FORM_HANDLER", "service": "amn-form-handler-dev" } ] }, "prod": { "name": "amn-prod", "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 }, "traces": { "enabled": true, "head_sampling_rate": 0.01 } }, "d1_databases": [ { "binding": "AUTH_DB", "database_name": "amn-auth-db-prod", "database_id": "<your-d1-database-id-prod>", "migrations_dir": "drizzle" } ], "kv_namespaces": [ { "binding": "AUTH_KV", "id": "<your-kv-namespace-id-prod>" } ], "services": [ { "binding": "FORM_HANDLER", "service": "amn-form-handler-prod" } ] } }}3.2. Environment Variables (.env)
Section titled â3.2. Environment Variables (.env)â# Better AuthBETTER_AUTH_SECRET=<random-32-char-secret>BETTER_AUTH_URL=http://localhost:4321
# CloudflareCLOUDFLARE_ACCOUNT_ID=<your-account-id>AUTH_DB_ID=<your-d1-database-id>AUTH_KV_ID=4a990eb34db9430284b0961ac5d107dd
# EnvironmentENVIRONMENT=dev4. Création des Ressources Cloudflare (CODE)
Section titled â4. CrĂ©ation des Ressources Cloudflare (CODE)â4.1. Script de CrĂ©ation des Ressources
Section titled â4.1. Script de CrĂ©ation des RessourcesâConformĂ©ment Ă lâapproche du projet, les ressources Cloudflare sont créées via script bash automatisĂ© :
#!/bin/bash# Création des ressources Cloudflare pour Better Auth (D1 + KV)# Usage: ./scripts/create-cloudflare-resources.sh --env=dev
set -e
ENV="dev"
while [[ $# -gt 0 ]]; do case $1 in --env=*) ENV="${1#*=}" shift ;; *) echo "â Argument inconnu: $1" echo "Usage: ./scripts/create-cloudflare-resources.sh --env=dev" exit 1 ;; esacdone
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"PROJECT_ROOT="$ROOT_DIR/.."cd "$PROJECT_ROOT"
if ! npx wrangler whoami >/dev/null 2>&1; then echo "â Wrangler n'est pas connectĂ©. Connectez-vous avec: npx wrangler login" exit 1fi
echo "=== Création des ressources Cloudflare pour Better Auth (environnement: $ENV) ==="echo ""
# CrĂ©ation D1 Databaseecho "đ CrĂ©ation D1 Database 'amn-auth-db-$ENV'..."D1_OUTPUT=$(npx wrangler d1 create "amn-auth-db-$ENV" 2>&1)D1_ID=$(echo "$D1_OUTPUT" | grep -oP 'database_id = "\K[^"]+')
if [ -z "$D1_ID" ]; then echo "â ïž Erreur lors de la crĂ©ation D1 ou base existe dĂ©jĂ " exit 1fi
echo "â
D1 Database créée avec ID: $D1_ID"echo ""
# CrĂ©ation KV Namespace (si nĂ©cessaire pour prod)if [ "$ENV" = "prod" ]; then echo "đïž CrĂ©ation KV Namespace 'amn-auth-kv-$ENV'..." KV_OUTPUT=$(npx wrangler kv namespace create "amn-auth-kv-$ENV" 2>&1) KV_ID=$(echo "$KV_OUTPUT" | grep -oP 'id = "\K[^"]+')
if [ -z "$KV_ID" ]; then echo "â ïž Erreur lors de la crĂ©ation KV ou namespace existe dĂ©jĂ " exit 1 fi
echo "â
KV Namespace créé avec ID: $KV_ID"else KV_ID="4a990eb34db9430284b0961ac5d107dd" echo "â
Utilisation KV existant (dev): $KV_ID"fi
echo ""echo "=== RĂ©sumĂ© des ressources créées ==="echo "D1 Database ID: $D1_ID"echo "KV Namespace ID: $KV_ID"echo ""echo "â ïž IMPORTANT: Mettez Ă jour wrangler.jsonc avec ces IDs"echo ""4.2. ExĂ©cution du Script
Section titled â4.2. ExĂ©cution du Scriptâ# CrĂ©er les ressources pour dev./scripts/create-cloudflare-resources.sh --env=dev
# Créer les ressources pour prod./scripts/create-cloudflare-resources.sh --env=prod4.3. Mise à jour wrangler.jsonc
Section titled â4.3. Mise Ă jour wrangler.jsoncâAprĂšs lâexĂ©cution du script, mettre Ă jour les IDs dans apps/web/wrangler.jsonc :
"d1_databases": [ { "binding": "AUTH_DB", "database_name": "amn-auth-db", "database_id": "<votre-d1-id-ici>", // Remplacer par l'ID retourné "migrations_dir": "drizzle" }],"kv_namespaces": [ { "binding": "AUTH_KV", "id": "4a990eb34db9430284b0961ac5d107dd" // Existant pour dev }]4.4. Migrations D1 via Script
Section titled â4.4. Migrations D1 via ScriptâConformĂ©ment Ă lâapproche du projet, les migrations D1 sont effectuĂ©es via script bash automatisĂ© :
Génération du schéma :
./scripts/migrate-d1.sh --env=dev --action=generateApplication des migrations :
# Environnement dev./scripts/migrate-d1.sh --env=dev --action=apply
# Environnement prod./scripts/migrate-d1.sh --env=prod --action=applyLe script vérifie automatiquement :
- Que wrangler est connecté
- Que Better Auth Cloudflare CLI est installé
- Lâenvironnement cible (dev/prod)
- Lâaction demandĂ©e (generate/apply)
5. Configuration Better Auth (CODE)
Section titled â5. Configuration Better Auth (CODE)â5.1. Installation des DĂ©pendances
Section titled â5.1. Installation des DĂ©pendancesâcd apps/webpnpm add better-auth better-auth-cloudflare drizzle-ormpnpm add -D @better-auth/drizzle-adapter drizzle-kit5.2. Configuration Better Auth
Section titled â5.2. Configuration Better Authâimport { betterAuth } from "better-auth";import { withCloudflare } from "better-auth-cloudflare";import { drizzleAdapter } from "@better-auth/drizzle-adapter";import { drizzle } from "drizzle-orm/d1";import * as schema from "./db/schema";
export function createAuth(env: any) { const db = drizzle(env.AUTH_DB, { schema });
return betterAuth({ ...withCloudflare( { d1: { db, options: { usePlural: true } }, kv: env.AUTH_KV, autoDetectIpAddress: true }, { database: drizzleAdapter(db, { provider: "sqlite" }), session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24 // 1 day }, advanced: { cookiePrefix: "amn-auth", useSecureCookies: env.ENVIRONMENT === 'prod' }, account: { accountLinking: { enabled: false } } } ) });}5.3. Schéma Drizzle (Auto-généré)
Section titled â5.3. SchĂ©ma Drizzle (Auto-gĂ©nĂ©rĂ©)âBetter Auth gĂ©nĂšre automatiquement le schĂ©ma via son CLI. Le fichier gĂ©nĂ©rĂ© sera :
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
export const user = sqliteTable("user", { id: text("id").primaryKey(), email: text("email").notNull().unique(), emailVerified: integer("emailVerified", { mode: "boolean" }).default(false), name: text("name"), image: text("image"), createdAt: integer("createdAt").notNull(), updatedAt: integer("updatedAt").notNull(),});
export const session = sqliteTable("session", { id: text("id").primaryKey(), userId: text("userId").notNull().references(() => user.id, { onDelete: "cascade" }), expiresAt: integer("expiresAt").notNull(), token: text("token").notNull().unique(), ipAddress: text("ipAddress"), userAgent: text("userAgent"), createdAt: integer("createdAt").notNull(), updatedAt: integer("updatedAt").notNull(),});
export const account = sqliteTable("account", { id: text("id").primaryKey(), userId: text("userId").notNull().references(() => user.id, { onDelete: "cascade" }), accountId: text("accountId").notNull(), providerId: text("providerId").notNull(), accessToken: text("accessToken"), refreshToken: text("refreshToken"), idToken: text("idToken"), expiresAt: integer("expiresAt"), password: text("password"), createdAt: integer("createdAt").notNull(), updatedAt: integer("updatedAt").notNull(),});
export const verification = sqliteTable("verification", { id: text("id").primaryKey(), identifier: text("identifier").notNull(), value: text("value").notNull(), expiresAt: integer("expiresAt").notNull(), createdAt: integer("createdAt").notNull(), updatedAt: integer("updatedAt").notNull(),});6. Intégration avec Middleware Astro (CODE)
Section titled â6. IntĂ©gration avec Middleware Astro (CODE)â6.1. Configuration TypeScript
Section titled â6.1. Configuration TypeScriptâinterface Env { AUTH_DB: D1Database; AUTH_KV: KVNamespace; ENVIRONMENT: 'dev' | 'prod';}6.2. Middleware Utilisant Better Auth
Section titled â6.2. Middleware Utilisant Better Authâimport { defineMiddleware } from 'astro:middleware';import { createAuth } from './auth/index';
export const onRequest = defineMiddleware(async (context, next) => { const { pathname } = context.url;
// Pour les routes de documentation privées if (pathname.startsWith('/docs/') || pathname.startsWith('/gettingStarted/')) { const auth = createAuth(context.locals.runtime.env); const session = await auth.api.getSession({ headers: context.request.headers });
if (!session) { return context.redirect(`/login?redirectTo=${encodeURIComponent(pathname)}`); }
context.locals.user = session.user; }
return next();});7. Contrats dâEntrĂ©e/Sortie (SPEC)
Section titled â7. Contrats dâEntrĂ©e/Sortie (SPEC)â7.1. Wrangler Configuration
Section titled â7.1. Wrangler Configurationâ| Binding | Type | Resource | Description |
|---|---|---|---|
AUTH_DB |
D1 | amn-auth-db |
Base de données users/sessions |
AUTH_KV |
KV | AUTH_SESSIONS_KV |
Secondary storage cache |
7.2. Environment Variables
Section titled â7.2. Environment Variablesâ| Variable | Type | Description | Exemple |
|---|---|---|---|
BETTER_AUTH_SECRET |
string | Secret pour signing cookies | random-32-char-secret |
BETTER_AUTH_URL |
string | URL de lâapplication | http://localhost:4321 |
AUTH_DB_ID |
string | ID de la base D1 | xxxxxxxx-xxxx-xxxx-xxxx |
AUTH_KV_ID |
string | ID du namespace KV | 4a990eb34db9430284b0961ac5d107dd |
7.3. Better Auth Configuration
Section titled â7.3. Better Auth Configurationâ| Option | Valeur | Description |
|---|---|---|
session.expiresIn |
604800 (7 days) |
Durée de vie session |
session.updateAge |
86400 (1 day) |
Fréquence rafraßchissement |
cookiePrefix |
amn-auth |
Préfixe cookies |
useSecureCookies |
env === 'prod' |
Cookies HTTPS en prod |
8. Sécurité
Section titled â8. SĂ©curitĂ©â- Secret Generation : Utiliser
crypto.randomUUID()ou outil de génération de secrets - Environment Variables : Jamais commitées, utiliser
.env+.env.example - D1 Backups : Configurer backups automatiques Cloudflare
- KV TTL : Sessions en KV avec TTL approprié
- Encryption : Better Auth gĂšre le hash des passwords automatiquement
9. Migration depuis Auth-Handler (CODE)
Section titled â9. Migration depuis Auth-Handler (CODE)â9.1. Script Migration Sessions
Section titled â9.1. Script Migration Sessionsâimport { createClient } from '@cloudflare/d1';
export async function migrateSessions() { // Lire les sessions depuis KV existant // Créer les utilisateurs et sessions dans D1 // Mettre à jour les cookies}9.2. Rollback Plan
Section titled â9.2. Rollback Planâ# En cas de problĂšme, restaurer l'ancien systĂšme# 1. Restaurer configuration wrangler.toml (sans D1)# 2. RedĂ©marrer auth-handler# 3. Restaurer backup D1 si nĂ©cessaire10. Tests Attendus (TEST)
Section titled â10. Tests Attendus (TEST)â10.1. Tests Infrastructure
Section titled â10.1. Tests Infrastructureâ- D1 database créée et accessible
- KV namespace accessible
- Migrations appliquées avec succÚs
- Bindings wrangler corrects
10.2. Tests Better Auth
Section titled â10.2. Tests Better Authâ- Configuration Better Auth valide
- Connexion D1 fonctionnelle
- KV secondary storage actif
- Cookies générés correctement
10.3. Tests Intégration
Section titled â10.3. Tests IntĂ©grationâ- Middleware utilise Better Auth
- Sessions créées dans D1
- Cache KV fonctionnel
- Typecheck réussi
11. Documentation Utilisateur
Section titled â11. Documentation Utilisateurâ11.1. CrĂ©ation Ressources
Section titled â11.1. CrĂ©ation Ressourcesâ# CrĂ©er D1 databasewrangler d1 create amn-auth-db
# Mettre Ă jour wrangler.toml avec l'ID11.2. Migrations
Section titled â11.2. Migrationsâ# GĂ©nĂ©rer schĂ©manpx @better-auth-cloudflare/cli migrate --generate
# Appliquer migrationsnpx @better-auth-cloudflare/cli migrate --apply dev11.3. Dépannage
Section titled â11.3. DĂ©pannageâ- Erreur binding D1 : VĂ©rifier wrangler.toml et redĂ©marrer dev server
- Migrations échouent : Vérifier connectivity D1 et permissions
- KV non accessible : Vérifier ID KV namespace et binding
12. Historique des Modifications
Section titled â12. Historique des Modificationsâ| Date | Version | Description | Auteur |
|---|---|---|---|
| 2026-09-27 | 1.0 | Création initiale DAT Configuration D1 + KV | Team (Agent) |