vendredi 25 septembre 2026

À propos

Contact

Headless & API

Espace membres en headless : connexion et sessions des utilisateurs du front

Un espace membres sur un front découplé demande de repenser tout le parcours de connexion : stockage du jeton, rafraîchissement, déconnexion propre.

Par Clément Hadrot • 26 juillet 2022 • 5 min de lecture • Aucun commentaire
Espace membres en headless : connexion et sessions des utilisateurs du front

Un client gérant une plateforme de formation en ligne voulait un espace membres sur son nouveau front Next.js, où les utilisateurs se connectent pour accéder à leurs cours achetés. Contrairement à un site WordPress classique où wp_login_form() et le cookie de session gèrent tout automatiquement, un front découplé doit reconstruire l’intégralité du parcours : formulaire de connexion, stockage sûr du jeton d’authentification, rafraîchissement avant expiration, et déconnexion qui invalide réellement la session.

Cet article se concentre sur ce parcours utilisateur côté front, sans comparer les mécanismes d’authentification entre eux (JWT contre mots de passe d’application), un choix qui doit être fait en amont et qui fait l’objet d’un comparatif séparé.

Le formulaire de connexion

Le formulaire lui-même reste simple : un appel à l’API d’authentification choisie (ici, l’extension JWT Authentication for WP REST API, à titre d’exemple), qui renvoie un jeton en cas de succès.

async function seConnecter(identifiant, motDePasse) {
  const reponse = await fetch('https://exemple.fr/wp-json/jwt-auth/v1/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: identifiant, password: motDePasse }),
  });

  if (!reponse.ok) {
    const erreur = await reponse.json();
    throw new Error(erreur.message ?? 'Identifiants incorrects.');
  }

  const { token, user_email, user_display_name } = await reponse.json();
  return { token, email: user_email, nom: user_display_name };
}

Le message d’erreur renvoyé par cette extension distingue rarement « identifiant inconnu » de « mot de passe incorrect », par choix délibéré de sécurité (éviter de confirmer l’existence d’un compte à un attaquant) : côté front, il vaut mieux reprendre ce même message générique plutôt que d’essayer de le rendre plus précis.

Où stocker le jeton

C’est le point le plus sensible du parcours. Deux options courantes, avec des compromis différents :

StockageAvantageRisque
localStorageSimple à implémenter, accessible facilement en JavaScriptVulnérable en cas de faille XSS sur le site : un script injecté peut lire le jeton
Cookie httpOnly posé par le serveur du frontInaccessible au JavaScript, donc protégé contre le vol par XSSDemande un serveur (route API du front) pour poser et lire le cookie, pas compatible avec un export purement statique

Sur le projet de formation en ligne, où les cours accessibles représentaient une réelle valeur commerciale, j’ai opté pour un cookie httpOnly, posé par une route API interne à Next.js qui reçoit le jeton depuis le formulaire de connexion et le renvoie dans un cookie sécurisé, plutôt que de laisser le jeton transiter et rester stocké côté client en JavaScript.

L'essentiel à retenir : Le parcours de connexion se déroule entièrement côté front ; Stockage du jeton : ni localStorage naïf, ni cookie sans précaution ; Rafraîchissement et déconnexion à gérer explicitement
// pages/api/connexion.js (route API Next.js)
export default async function handler(req, res) {
  const { identifiant, motDePasse } = req.body;

  const reponseWp = await fetch('https://exemple.fr/wp-json/jwt-auth/v1/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username: identifiant, password: motDePasse }),
  });

  if (!reponseWp.ok) {
    return res.status(401).json({ erreur: 'Identifiants incorrects.' });
  }

  const { token } = await reponseWp.json();

  res.setHeader('Set-Cookie', [
    `jeton_session=${token}; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600`,
  ]);

  res.status(200).json({ succes: true });
}

Rafraîchir le jeton avant expiration

Un jeton JWT expire généralement après une durée configurée côté extension (7 jours par défaut pour JWT Authentication for WP REST API). Plutôt que de forcer une reconnexion brutale à l’expiration, un mécanisme de rafraîchissement transparent améliore nettement l’expérience :

async function rafraichirJetonSiNecessaire(jeton) {
  const { exp } = decoderJWT(jeton);
  const expireBientot = exp * 1000 - Date.now() < 5 * 60 * 1000; // moins de 5 min

  if (expireBientot) {
    const reponse = await fetch('/api/rafraichir-session', { method: 'POST' });
    if (!reponse.ok) {
      // Le rafraîchissement a échoué : forcer une reconnexion
      redirigerVersConnexion();
    }
  }
}

L'extension JWT Authentication for WP REST API standard ne propose pas nativement de jeton de rafraîchissement distinct : sur ce projet, la route de rafraîchissement rappelait simplement l'endpoint de connexion avec les identifiants stockés côté serveur de session, une solution pragmatique en attendant une extension plus complète gérant un vrai jeton de rafraîchissement séparé.

Déconnexion propre

Un jeton JWT reste valide jusqu'à son expiration naturelle, même après une « déconnexion » côté front qui se contente de supprimer le cookie ou l'entrée localStorage : le jeton lui-même n'est pas révoqué côté serveur. Pour une déconnexion réellement sûre (utile en cas de poste partagé, par exemple), il faut soit une liste de révocation côté WordPress, soit accepter cette limite connue des jetons JWT sans état.

export default function handler(req, res) {
  res.setHeader('Set-Cookie', [
    'jeton_session=; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=0',
  ]);
  res.status(200).json({ succes: true });
}
  • Toujours invalider le cookie ou le stockage côté client à la déconnexion, même si le jeton reste techniquement valide côté serveur.
  • Informer clairement l'utilisateur si une déconnexion « totale » (révocation) n'est pas garantie par le mécanisme choisi.
  • Prévoir une durée d'expiration courte si aucune révocation n'est en place, pour limiter la fenêtre de risque en cas de vol de jeton.

Un espace membres headless mal conçu échoue rarement sur la connexion elle-même : c'est presque toujours la déconnexion, le rafraîchissement silencieux ou la gestion d'un jeton expiré en plein milieu d'une session qui posent problème en production, des cas trop souvent testés en dernier.

En résumé

Construire un espace membres sur un front headless demande de reconstruire tout le parcours que WordPress gérait auparavant en coulisses : connexion, stockage sûr du jeton (avec une préférence pour un cookie httpOnly posé côté serveur plutôt qu'un localStorage exposé au JavaScript), rafraîchissement avant expiration, et une déconnexion qui reconnaît honnêtement les limites d'un jeton JWT sans mécanisme de révocation.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi