---
name: project_2fa
description: "Implémentation complète du 2FA (TOTP + email OTP) — DB, backend, frontend Login et MonCompte"
metadata: 
  node_type: memory
  type: project
  originSessionId: e9aff1a4-9c1c-4cab-b7ec-90146b832fb0
---

Fonctionnalité 2FA ajoutée en session juin 2026.

**DB (db/index.js)** — colonnes sur `users` : `totp_secret TEXT`, `totp_enabled INTEGER DEFAULT 0`. Tables : `two_fa_sessions` (session temporaire entre /login et /2fa/verify, 5 min), `two_fa_email_codes` (OTP email 6 chiffres, 5 min), `two_fa_trusted_devices` (appareils de confiance 30 jours, avec `user_agent` et `ip_address`).

**Backend (auth.js)** — routes :
- `POST /login` : si `totp_enabled` → vérifie `deviceToken` (header `X-Device-Token`), sinon retourne `{ requires2FA: true, sessionToken }`
- `GET /2fa/setup` : génère secret TOTP + QR code base64 (lib `otplib` API fonctionnelle)
- `POST /2fa/confirm-setup` : vérifie code, active 2FA
- `POST /2fa/disable` : désactive (mot de passe requis), efface tous les appareils de confiance
- `POST /2fa/send-email-code` : envoie OTP 6 chiffres par email (validité 5 min)
- `POST /2fa/verify` : vérifie code (TOTP ou email), émet JWT, crée `two_fa_trusted_devices` si `trustDevice=true`
- `GET /trusted-devices` : liste appareils de confiance actifs
- `DELETE /trusted-devices/:id` : révoque un appareil
- `DELETE /trusted-devices` : révoque tous

**Frontend** :
- `AuthContext.jsx` : `login(email, password, deviceToken)` retourne `{ requires2FA, sessionToken }` si 2FA actif ; nouvelle fonction `completeLogin(token, user)` appelée après vérification du code
- `Login.jsx` : machine à 3 états (`form` → `method` → `code`) ; countdown 5 min pour OTP email ; checkbox "Faire confiance 30 jours" ; `cl_device_token` stocké dans localStorage
- `MonCompte.jsx` > Sécurité : composant `TwoFASection` (QR code setup, clé manuelle, confirmation code, désactivation) + composant `TrustedDevicesSection` (liste appareils, badge APPAREIL ACTUEL, déconnexion individuelle ou tout)
- `api.js` : `authHeaders()` envoie automatiquement `X-Device-Token` si `cl_device_token` présent

**Why:** Sécurité renforcée, demande utilisateur.
**How to apply:** Toujours envoyer `X-Device-Token` depuis `authHeaders()` (déjà en place). Ne pas exposer les tokens bruts dans les réponses API.
