Ibexa Commerce 5 + Next.js : authentification client, VIP et commandes — REX headless

Ibexa Commerce 5 + Next.js : authentification client, VIP et commandes — REX headless

Dans le premier volet, nous avions construit un catalogue et un panier Next.js alimentés par l’API REST d’Ibexa Commerce 5. Il manquait encore une pièce essentielle : le client réel.

L’objectif de cette étape est simple à formuler : un visiteur se connecte depuis Next.js, Ibexa vérifie son identité, reconnaît son groupe commercial — ici vip — puis retourne uniquement ses commandes.

Le point important est architectural : Next.js ne remplace pas la sécurité d’Ibexa. Il fournit l’interface. Ibexa reste responsable de l’identité, des permissions, des groupes clients, des promotions et des commandes.

Architecture de la session client entre Next.js et Ibexa Commerce 5

Ce que nous obtenons

À la fin du parcours :

  • /login affiche le formulaire Next.js ;
  • POST /api/auth/session transmet les identifiants au serveur Ibexa ;
  • Ibexa crée une session REST et retourne un jeton CSRF ;
  • Next.js conserve la session dans des cookies HttpOnly ;
  • /account affiche le profil, le groupe VIP et l’historique ;
  • /api/storefront/orders ne retourne que les commandes autorisées ;
  • la déconnexion détruit réellement la session Ibexa ;
  • le checkout reste natif dans Ibexa.

Ce n’est donc pas une maquette : l’interface Next.js lit les données du projet Commerce réel.

Le flux en une minute

Navigateur
   │  identifiant + mot de passe
   ▼
Route Handler Next.js
   │  POST /api/ibexa/v2/user/sessions
   ▼
Ibexa Commerce 5
   │  cookie de session + jeton CSRF + utilisateur
   ▼
Cookies HttpOnly Next.js
   │
   ├── profil et groupe client
   ├── catalogue/prix contextualisés
   ├── panier et promotions
   └── commandes filtrées par les permissions Ibexa

Étape 1 — utiliser l’API de session d’Ibexa

Ibexa fournit le point d’entrée suivant :

POST /api/ibexa/v2/user/sessions
Accept: application/vnd.ibexa.api.Session+json
Content-Type: application/vnd.ibexa.api.SessionInput+json

Le corps attendu est volontairement petit :

{
  "SessionInput": {
    "login": "client.demo",
    "password": "<mot-de-passe>"
  }
}

La réponse contient trois informations utiles : le nom du cookie de session, son identifiant et le jeton CSRF. Le mot de passe n’est pas conservé.

Dans frontend-next/src/lib/ibexa-auth.ts, notre fonction loginToIbexa() encapsule cet échange. Elle refuse aussi une réponse incomplète : une session sans cookie ou sans jeton ne doit pas être considérée comme valide.

Étape 2 — pourquoi passer par un Route Handler Next.js ?

Le navigateur ne contacte pas directement l’API Ibexa. Il appelle :

POST /api/auth/session

Cette route serveur joue le rôle de Backend for Frontend :

  1. elle reçoit le formulaire ;
  2. elle appelle Ibexa côté serveur ;
  3. elle écrit les cookies sécurisés ;
  4. elle retourne uniquement le profil utile à l’interface.

Les cookies sont configurés avec HttpOnly et SameSite=Lax. Le JavaScript du navigateur ne peut donc pas lire le cookie de session.

const COOKIE_OPTIONS = {
  httpOnly: true,
  sameSite: "lax",
  secure: process.env.NODE_ENV === "production",
  path: "/",
};

En production HTTPS, secure devient automatiquement actif.

Étape 3 — garder une seule identité pour tout le Commerce

Le même cookie Ibexa est réutilisé pour :

  • charger le profil ;
  • résoudre le groupe client ;
  • contextualiser le catalogue et les prix ;
  • manipuler le panier ;
  • lire les commandes.

C’est essentiel. Si Next.js créait sa propre identité indépendante, le moteur Commerce ne saurait pas quel groupe, quel prix ou quelle promotion appliquer.

Lors de la connexion, nous supprimons le panier anonyme courant. Pourquoi ? Un panier appartient à une session et à un propriétaire précis. Dans un vrai projet, on pourrait développer une stratégie de fusion ; pour cette formation, repartir sur un panier client propre rend le comportement explicite et sûr.

Étape 4 — reconnaître le groupe VIP

Le Content Type client contient un champ customer_group de type ibexa_customer_group. Le profil REST fournit l’identifiant numérique du groupe ; notre serveur charge ensuite la ressource Customer Group pour récupérer son identifiant métier, ici vip.

Utilisateur Ibexa
   └── champ customer_group
          └── Customer Group « vip »
                 ├── contexte de prix
                 └── promotions autorisées

Le groupe n’est donc ni un rôle Symfony ni une simple étiquette visuelle. C’est une donnée Commerce utilisée par les moteurs de prix et de promotions.

Dans le panier, le client VIP voit un rappel : le code pédagogique VIP20 devient éligible à partir de 100 € HT. Ibexa, et non Next.js, décide finalement si les conditions sont remplies.

Étape 5 — afficher les commandes sans exposer les données sensibles

L’espace client appelle une route locale :

GET /api/storefront/orders

Celle-ci relaie la requête vers :

GET /api/ibexa/v2/orders/orders?limit=20&offset=0
Accept: application/vnd.ibexa.api.OrderList+json

L’API REST d’Ibexa applique les permissions du client connecté. Next.js normalise ensuite la réponse et n’envoie à l’écran que :

  • l’identifiant abrégé ;
  • la date ;
  • le statut ;
  • le nombre d’articles ;
  • le total TTC ;
  • les noms de produits.

Les adresses, emails et numéros de téléphone présents dans le contexte de commande ne sont pas transmis au composant React. Cette réduction de données est une bonne pratique importante dans un storefront headless.

Étape 6 — une vraie déconnexion

Effacer seulement les cookies Next.js ne suffit pas. La route de déconnexion appelle aussi :

DELETE /api/ibexa/v2/user/sessions/{sessionId}
X-CSRF-Token: {token}

Ibexa invalide la session, puis Next.js efface ses cookies locaux. Notre test final confirme ensuite que l’accès aux commandes retourne 401 Unauthorized.

Pourquoi conserver le checkout natif ?

Nous avons volontairement gardé le checkout dans Ibexa. Il concentre les étapes les plus sensibles :

  • adresses de facturation et de livraison ;
  • méthodes de livraison ;
  • méthodes de paiement ;
  • création de commande ;
  • transitions de statuts.

Un checkout entièrement headless est possible, mais il mérite un chantier distinct. Ici, Next.js gère la découverte, le compte et le panier ; Ibexa reprend la main au moment de finaliser l’achat.

Tests réellement exécutés

Le parcours a été vérifié ainsi :

Connexion VIP                    HTTP 200
Groupe client reconnu           vip
Liste des commandes             HTTP 200
Déconnexion                     HTTP 200
Commandes après déconnexion     HTTP 401
ESLint                          OK
Build Next.js de production     OK

Le 401 final est volontaire : il prouve que la protection fonctionne.

Ce qu’un développeur Symfony doit retenir

Le parallèle avec Symfony est direct :

Symfony classique Storefront Next.js + Ibexa
Firewall et session Symfony Firewall et session REST Ibexa
Contrôleur Route Handler Next.js
Twig Composants React
Service métier API et services Commerce Ibexa
Cookie de session Cookie Ibexa conservé côté serveur
Voter / permissions Permissions Repository et Commerce

La couche de présentation change, pas la source d’autorité.

Fichiers principaux

frontend-next/src/lib/ibexa-auth.ts
frontend-next/src/app/api/auth/session/route.ts
frontend-next/src/app/api/storefront/orders/route.ts
frontend-next/src/app/login/page.tsx
frontend-next/src/app/account/page.tsx
frontend-next/src/components/LoginForm.tsx
frontend-next/src/components/AccountView.tsx
frontend-next/src/components/AccountNav.tsx

Le code complet est disponible dans le dépôt public formation-ibexa.

Conclusion

Cette étape transforme notre storefront en véritable application client. Next.js ne se contente plus d’afficher un catalogue : il porte une session Ibexa, respecte le contexte commercial VIP et affiche un historique de commandes filtré.

La règle d’architecture reste simple : Next.js présente, Ibexa authentifie et décide.

La prochaine étape quittera volontairement le périmètre Commerce pur : nous explorerons les AI Actions d’Ibexa 5, avant d’aborder Ibexa Connect, Engage et les recommandations Raptor selon les accès disponibles.