Skip to Content
Wagoo SaaS 1.0.25 is released 🎉
02 ArchitectureSystème d'authentificationSystème d'Authentification

Système d’Authentification

Overview - better-auth

Wagoo utilise better-auth, un framework d’authentification moderne et sécurisé.

Plugins Activés

import { betterAuth } from "better-auth"; import { twoFactor } from "better-auth/plugins/two-factor"; import { passkey } from "better-auth/plugins/passkey"; import { magicLink } from "better-auth/plugins/magic-link"; import { emailVerification } from "better-auth/plugins/email-verification"; import { socialProviders } from "better-auth/plugins/social-providers"; export const auth = betterAuth({ database: prisma, secret: process.env.BETTER_AUTH_SECRET, plugins: [ twoFactor(), passkey(), magicLink(), emailVerification(), socialProviders({ providers: { github: { clientId: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET }, google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET } } }) ] });

Flux d’Authentification

Sign Up (Inscription)

1. User → Remplit email + password 2. Form validation (client + serveur) 3. Vérifie l'unicité de l'email 4. Hash le password avec bcrypt 5. Crée l'user en DB 6. Envoie email de vérification 7. Session créée 8. Redirection vers dashboard/verify-email

Sign In (Connexion)

1. User → Remplit email + password 2. Trouve l'user par email 3. Compare password avec bcrypt 4. Crée une session 5. Set cookie de session 6. Redirection vers dashboard

Sign Out (Déconnexion)

1. Supprime la session en DB 2. Efface le cookie 3. Redirection vers home

Méthodes d’authentification

1. Email/Password

Prérequis : Email + Password

// Sign Up const { user, session } = await auth.signUp({ email: "user@example.com", password: "SecurePassword123" }); // Sign In const { user, session } = await auth.signIn({ email: "user@example.com", password: "SecurePassword123" });

Prérequis : Juste l’email

// Envoyer un lien magique await auth.sendMagicLink({ email: "user@example.com" }); // User clique le lien → Connexion automatique

3. OAuth (GitHub)

Prérequis : Compte GitHub

// Redirection vers GitHub window.location.href = auth.getOAuthRedirectURL("github"); // Après authentification GitHub // → Session créée automatiquement

4. OAuth (Google)

Prérequis : Compte Google

// Redirection vers Google window.location.href = auth.getOAuthRedirectURL("google"); // Après authentification Google // → Session créée automatiquement

5. Passkeys (Biométrique)

Prérequis : Appareil avec support passkey

// Enregistrer un passkey await auth.registerPasskey(); // Sign in avec passkey await auth.signInWithPasskey();

6. 2FA (TOTP)

Prérequis : Email/Password + Authenticator app

// Activer 2FA const { secret, qrCode } = await auth.enableTwoFactor(); // Vérifier le code TOTP await auth.verifyTwoFactor({ code: "123456" }); // Sign In avec 2FA const { user, session } = await auth.signIn({ email: "user@example.com", password: "SecurePassword123", totpCode: "123456" });

Tables d’authentification

better-auth crée automatiquement ces tables :

model Account { id String @id @default(cuid()) userId String type String provider String providerAccountId String refreshToken String? accessToken String? expiresAt Int? tokenType String? scope String? idToken String? sessionToken String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation("accounts", fields: [userId], references: [id], onDelete: Cascade) @@unique([provider, providerAccountId]) } model Session { id String @id @default(cuid()) userId String expiresAt DateTime token String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation("sessions", fields: [userId], references: [id], onDelete: Cascade) } model Verification { id String @id @default(cuid()) identifier String token String @unique expires DateTime createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([identifier, token]) }

Middleware d’authentification

Protéger les routes

// app/api/projects/route.ts import { auth } from "@/lib/auth"; export async function GET(request: Request) { // Récupérer la session const session = await auth.getSession(request); if (!session) { return Response.json( { error: "Unauthorized" }, { status: 401 } ); } // Session valide, continuer... const projects = await prisma.project.findMany({ where: { ownerId: session.user.id } }); return Response.json(projects); }

Protéger les pages

// app/dashboard/page.tsx import { redirect } from "next/navigation"; import { auth } from "@/lib/auth"; export default async function DashboardPage() { const session = await auth.getSession(); if (!session) { redirect("/auth/sign-in"); } return <div>Welcome {session.user.email}</div>; }

Sécurité

Hachage des mots de passe

✅ Utilise bcrypt avec salt aléatoire ✅ Les mots de passe ne sont jamais stockés en clair ✅ Difficile à craquer (millions d’années en brute force)

Tokens de session

✅ Tokens générés aléatoirement (256 bits) ✅ Stockés en httpOnly cookies (inaccessibles en JavaScript) ✅ Expiration configurable (défaut : 7 jours)

Protection CSRF

✅ Intégré dans Next.js ✅ Cookies SameSite=Strict ✅ CSRF tokens en POST requests

Email verification

✅ Tokens d’vérification uniques ✅ Expiration après 24h ✅ Invalide après utilisation

Rate limiting (recommandé)

// Limiter les tentatives de sign-in import { Ratelimit } from "@upstash/ratelimit"; const ratelimit = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(5, "10 m"), }); const { success } = await ratelimit.limit(email); if (!success) return Response.json({ error: "Too many requests" }, { status: 429 });

Configuration des OAuth

GitHub

  1. Settings → Developer settings → New OAuth App 
  2. Authorization callback URL: http://localhost:3000/api/auth/callback/github
  3. Copier Client ID et Client Secret dans .env.local

Google

  1. Google Cloud Console → New Project 
  2. APIs & Services → Credentials
  3. Authorized redirect URI: http://localhost:3000/api/auth/callback/google
  4. Copier Client ID et Secret dans .env.local

Session & Cookies

better-auth gère automatiquement :

✅ Création de sessions ✅ Stockage sécurisé des cookies ✅ Refresh tokens ✅ Expiration des sessions

Exemple complet : Sign Up

// app/auth/sign-up/page.tsx "use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; export default function SignUpPage() { const router = useRouter(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); setError(""); try { const response = await fetch("/api/auth/sign-up", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }) }); if (!response.ok) { const data = await response.json(); setError(data.error || "Une erreur est survenue"); return; } // Redirection vers verify email router.push("/auth/verify-email"); } finally { setLoading(false); } }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required /> {error && <p style={{ color: "red" }}>{error}</p>} <button type="submit" disabled={loading}> {loading ? "Inscription..." : "S'inscrire"} </button> </form> ); }

Voir Sécurité pour les bonnes pratiques de sécurité supplémentaires.

Last updated on