Files
core/src/features/auth/README.md
T
hykocx abd9d651dc feat(auth): add user invitation flow with account setup
- add `createAccountSetup`, `verifyAccountSetupToken`, `deleteAccountSetupToken` to verifications core
- add `completeAccountSetup` function to auth core for password creation on invite
- add `InvitationEmail` template for sending invite links
- add `SetupAccountPage` client page for invited users to set their password
- add `UserCreateModal` admin component to invite new users
- wire invitation action and API endpoint in auth feature
- update admin `UsersPage` to include user creation modal
- update auth and admin README docs
2026-04-25 09:03:15 -04:00

10 KiB

Auth

Ce répertoire gère l'authentification : inscription, connexion, sessions, réinitialisation de mot de passe, vérification d'adresse courriel et gestion du profil. Il expose des server actions Next.js, des routes API REST et des composants de pages prêts à l'emploi.


Structure

src/features/auth/
├── index.js                      barrel serveur
├── actions.js                    server actions Next.js ('use server')
├── api.js                        routes API REST (users, roles)
├── auth.js                       register, login, resetPassword, updateUser, completeAccountSetup
├── session.js                    createSession, validateSession, deleteSession
├── email.js                      tokens de vérification + envoi des e-mails
├── password.js                   hashPassword, verifyPassword, generateToken
├── db.js                         createTables, dropTables
├── storage-policies.js           politiques d'accès au stockage
├── AuthPage.server.js            page RSC racine (route catch-all)
├── AuthPage.client.js            shell client
├── GUIDE-custom-login.md         guide pour les pages personnalisées
├── components/
│   └── AuthPageHeader.js
├── pages/
│   ├── index.js                  re-export
│   ├── LoginPage.client.js
│   ├── RegisterPage.client.js
│   ├── ForgotPasswordPage.client.js
│   ├── ResetPasswordPage.client.js
│   ├── ConfirmEmailPage.client.js
│   ├── SetupAccountPage.client.js
│   └── LogoutPage.client.js
└── templates/
    ├── VerificationEmail.js
    ├── PasswordResetEmail.js
    ├── PasswordChangedEmail.js
    ├── EmailChangeConfirmEmail.js
    ├── EmailChangeNotifyEmail.js
    └── InvitationEmail.js

Import

import { getSession, loginAction, logoutAction } from '@zen/core/features/auth/actions';
import { LoginPage, RegisterPage } from '@zen/core/features/auth/pages';
import { validateSession, createSession } from '@zen/core/features/auth';

Pages intégrées

La route catch-all app/auth/[...auth]/page.js suffit pour exposer toutes les pages sans configuration supplémentaire.

// app/auth/[...auth]/page.js
export { default } from '@zen/core/features/auth/server';
Route Page
/auth/login Connexion
/auth/register Inscription
/auth/forgot Mot de passe oublié
/auth/reset Réinitialisation du mot de passe
/auth/confirm Vérification de l'adresse courriel
/auth/setup Configuration du compte après invitation admin
/auth/logout Déconnexion

Server actions

Toutes les actions sont dans @zen/core/features/auth/actions. Elles attendent un FormData sauf getSession, setSessionCookie et refreshSessionCookie.

getSession()

Lit le cookie de session et retourne la session courante, ou null si l'utilisateur n'est pas connecté. Renouvelle automatiquement le cookie si la session a été rafraîchie.

const session = await getSession();
if (!session?.user) redirect('/auth/login');
// session.user, session.session disponibles

loginAction(formData)

Authentifie l'utilisateur et pose un cookie HttpOnly. Applique le rate limiting par IP et les vérifications anti-bot.

const result = await loginAction(formData);
// { success: true, user } ou { success: false, error }

registerAction(formData)

Crée un compte et envoie l'e-mail de vérification.

Champ Description
email Adresse courriel
password Mot de passe
name Nom d'affichage

logoutAction()

Invalide la session en base et supprime le cookie.


forgotPasswordAction(formData)

Envoie un lien de réinitialisation si un compte existe pour l'adresse fournie. La réponse ne révèle pas si le compte existe.


resetPasswordAction(formData)

Vérifie le token puis met à jour le mot de passe.

Champ Description
email Adresse courriel
token Token reçu par e-mail
newPassword Nouveau mot de passe

verifyEmailAction(formData)

Vérifie le token de confirmation et marque l'adresse comme vérifiée.

Champ Description
email Adresse courriel
token Token reçu par e-mail

setupAccountAction(formData)

Vérifie le token d'invitation, crée le compte credential et marque l'adresse comme vérifiée. Appelée depuis /auth/setup après qu'un admin a créé le compte sans mot de passe.

Champ Description
email Adresse courriel
token Token reçu dans le courriel d'invitation
newPassword Mot de passe choisi
confirmPassword Confirmation du mot de passe

setSessionCookie(token)

Valide le token contre la base avant de l'écrire dans le cookie HttpOnly. À utiliser après une authentification externe ou OAuth.


refreshSessionCookie(token)

Revalide le token et prolonge la durée de vie du cookie (30 jours).


Routes API REST

Les routes sont enregistrées automatiquement sous le préfixe /zen/api. L'authentification est appliquée par le routeur avant chaque handler.

Utilisateurs

Méthode Route Auth Description
GET /zen/api/users admin Liste paginée des utilisateurs
POST /zen/api/users admin Créer un utilisateur (avec ou sans invitation)
GET /zen/api/users/:id admin Détail d'un utilisateur
PUT /zen/api/users/:id admin Modifier name, role, email_verified
PUT /zen/api/users/:id/email admin Changer l'adresse courriel
PUT /zen/api/users/:id/password admin Définir un mot de passe
POST /zen/api/users/:id/send-password-reset admin Envoyer un lien de réinitialisation
GET /zen/api/users/:id/roles admin Lister les rôles de l'utilisateur
POST /zen/api/users/:id/roles admin Assigner un rôle
DELETE /zen/api/users/:id/roles/:roleId admin Révoquer un rôle

Profil (utilisateur connecté)

Méthode Route Description
PUT /zen/api/users/profile Modifier le nom
POST /zen/api/users/profile/email Initier un changement d'adresse courriel
GET /zen/api/users/email/confirm Confirmer le changement d'adresse
POST /zen/api/users/profile/password Changer le mot de passe
POST /zen/api/users/profile/picture Téléverser une photo de profil
DELETE /zen/api/users/profile/picture Supprimer la photo de profil
GET /zen/api/users/profile/sessions Lister les sessions actives
DELETE /zen/api/users/profile/sessions Révoquer toutes les sessions
DELETE /zen/api/users/profile/sessions/:sessionId Révoquer une session

Rôles

Méthode Route Description
GET /zen/api/roles Lister les rôles
POST /zen/api/roles Créer un rôle
GET /zen/api/roles/:id Détail d'un rôle
PUT /zen/api/roles/:id Modifier un rôle
DELETE /zen/api/roles/:id Supprimer un rôle

Invitation par l'admin

Un administrateur peut créer un utilisateur depuis /admin/users → Nouvel utilisateur. Deux flux selon si un mot de passe est fourni :

Avec mot de passe : l'utilisateur est créé avec email_verified = true et un compte credential. Il peut se connecter immédiatement.

Sans mot de passe : l'utilisateur est créé avec email_verified = false et aucun compte credential. Un token account_setup (48 h) est généré et un courriel d'invitation est envoyé. L'utilisateur clique sur le lien /auth/setup?email=X&token=Y, choisit son mot de passe, et le compte est activé (email_verified = true) en une seule étape — le passage par le lien vaut confirmation du courriel.

Admin crée l'utilisateur (sans mdp)
  → POST /zen/api/users
  → zen_auth_users créé (email_verified: false)
  → token account_setup enregistré dans zen_auth_verifications (48 h)
  → courriel InvitationEmail envoyé

Utilisateur clique sur le lien /auth/setup
  → SetupAccountPage (setupAccountAction)
  → token vérifié
  → zen_auth_accounts créé avec mot de passe haché
  → email_verified = true
  → token supprimé
  → redirection vers /auth/login

Sécurité

Rate limiting par IP. Les actions register, login, forgot_password, reset_password et verify_email sont limitées par adresse IP. Quand l'IP est inconnue (pas de proxy configuré), le rate limiting est suspendu et un avertissement opérateur est émis une seule fois. Activer avec ZEN_TRUST_PROXY=true derrière un reverse proxy vérifié.

Champs anti-bot. Chaque formulaire embarque un champ honeypot (_hp) et un timestamp de chargement (_t). Une soumission trop rapide (moins de 1,5 s), trop ancienne (plus de 10 min) ou avec un honeypot rempli est rejetée.

Cookie HttpOnly. Le token de session n'est jamais exposé à JavaScript. setSessionCookie et refreshSessionCookie valident le token en base avant d'écrire le cookie pour éviter qu'un token arbitraire soit accepté.

Erreurs opaques. Les erreurs internes sont loguées côté serveur et remplacées par un message générique côté client. Seules les UserFacingError (token expiré, etc.) remontent verbatim.


Base de données

db.js expose createTables() et dropTables(), appelés par initializeZen().

Table Contenu
zen_auth_users Utilisateurs (id, email, name, role, email_verified, image)
zen_auth_sessions Sessions actives avec IP et user-agent
zen_auth_accounts Comptes liés à un provider (credential, OAuth)
zen_auth_verifications Tokens de vérification d'e-mail et de réinitialisation

Pages personnalisées

Pour envelopper les pages auth dans un layout existant, voir GUIDE-custom-login.md. Le guide couvre le pattern serveur/client, les props de chaque composant et la protection de route.