Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
JavaScript

Les cookies en JavaScript

Découvrez les cookies : ce qu'ils sont, comment ils circulent entre le navigateur et le serveur (Set-Cookie et Cookie), et comment les créer, lire, modifier et supprimer en JavaScript avec document.co...

0 chapitres 0 QCM Accès gratuit
Dans cet article

À propos de ce cours

Découvrez les cookies : ce qu'ils sont, comment ils circulent entre le navigateur et le serveur (Set-Cookie et Cookie), et comment les créer, lire, modifier et supprimer en JavaScript avec document.cookie. La leçon détaille les attributs max-age, path, Secure, SameSite et HttpOnly, propose une petite bibliothèque de fonctions et un bandeau de consentement complet, rappelle les obligations légales, et présente l'actualité : maintien des cookies tiers dans Chrome et Cookie Store API, Baseline depuis 2025. Avec des activités corrigées.
  1. Objectifs

    • Comprendre ce qu'est un cookie, comment il circule entre le navigateur et le serveur, et à quoi il sert.
    • Créer, lire, modifier et supprimer un cookie en JavaScript avec document.cookie.
    • Choisir les bons attributs : max-age, path, Secure, SameSite, et comprendre HttpOnly.
    • Connaître les règles de consentement et la Cookie Store API, l'API moderne des cookies.
  2. Le stockage dans le navigateur : vue d'ensemble

    • Une page web perd toutes ses variables JavaScript dès qu'on la recharge. Pour se souvenir d'un thème, d'un panier ou d'une liste de tâches, il faut stocker les données quelque part.
    • Le navigateur propose quatre solutions, étudiées dans ce chapitre : les cookies (cette leçon), le localStorage et le sessionStorage (leçon 2) et IndexedDB (leçon 3).
    • Toutes ces données sont rangées par site: un site ne peut pas lire les données d'un autre site.

    Comparaison des cookies, du localStorage, du sessionStorage et d'IndexedDB

    • Un cookie est un petit texte (environ 4 Ko au maximum) de la forme nom=valeur, enregistré par le navigateur pour un site donné.
    • Inventés en 1994 par Lou Montulli, chez Netscape, ils servaient à mémoriser le contenu d'un panier. Le protocole HTTP n'ayant aucune mémoire, il fallait un moyen de reconnaître un visiteur d'une page à l'autre.
    • Leur particularité : le navigateur les renvoie automatiquement au serveur à chaque requête vers le site. C'est ce qui les rend indispensables pour les sessions (rester connecté), et c'est aussi leur défaut : des cookies trop gros alourdissent chaque échange.
    • Usages principaux :
    UsageExempleQui le crée ?
    SessionIdentifiant qui prouve que vous êtes connectéLe serveur (en HttpOnly)
    PréférencesLangue, thème, ville choisieLe serveur ou JavaScript
    ConsentementChoix de l'utilisateur dans le bandeau cookiesJavaScript
    Mesure d'audience, publicitéStatistiques de visite, suivi publicitaireSouvent un site tiers
    • Un cookie propriétaire (first-party) appartient au site visité. Un cookie tiers (third-party) est déposé par un autre domaine présent dans la page (régie publicitaire, bouton de réseau social) et permet de suivre l'internaute de site en site.
  3. Échange des cookies entre le navigateur et le serveur avec Set-Cookie et Cookie

  • Le serveur dépose un cookie avec l'en-tête de réponse Set-Cookie. JavaScript peut aussi en créer avec document.cookie.
  • Ensuite, à chaque requête vers ce site, le navigateur ajoute l'en-tête Cookie avec tous les cookies concernés.
  • Pour les voir : DevTools (F12) → onglet Application → Storage → Cookies. Vous pouvez les modifier ou les supprimer à la main. Dans l'onglet Réseau, cliquez sur une requête pour voir les en-têtes Cookie et Set-Cookie.
    • En lecture, document.cookie renvoie tous les cookies accessibles, dans une seule chaîne : "theme=sombre; consentement=oui". Les attributs (durée, chemin…) ne sont pas visibles.
    • En écriture, une affectation n'écrase pas tout : elle ajoute ou remplace un seul cookie, avec ses attributs.
    document.cookie = "theme=sombre; max-age=31536000; path=/; SameSite=Lax";
    document.cookie = "langue=fr; max-age=31536000; path=/; SameSite=Lax";
    
    console.log(document.cookie); // "theme=sombre; langue=fr"
    
    // Modifier : on réécrit le même nom (avec le même path)
    document.cookie = "theme=clair; max-age=31536000; path=/; SameSite=Lax";
    
    // Supprimer : durée de vie à 0
    document.cookie = "langue=; max-age=0; path=/";
    • Les caractères ;, ,, les espaces et les accents sont interdits dans la valeur : on les encode avec encodeURIComponent() et on les décode avec decodeURIComponent().
    1. AttributRôleConseil
      max-age=3600Durée de vie en secondes. Sans max-age ni expires, c'est un cookie de session, supprimé à la fermeture du navigateur.Préférez max-age à expires (date au format UTC, plus pénible à écrire).
      path=/Pages du site concernées. Par défaut : le dossier de la page courante.Mettez path=/ pour un cookie valable sur tout le site.
      domain=centre.tnRend le cookie visible aussi sur les sous-domaines (cours.centre.tn).À omettre dans la plupart des cas.
      SecureLe cookie n'est envoyé qu'en HTTPS. Toujours en production.
      SameSite=LaxContrôle l'envoi du cookie quand la requête vient d'un autre site: Strict (jamais), Lax (seulement en suivant un lien), None (toujours, avec Secure obligatoire).Lax: protège contre les attaques CSRF. Chrome l'applique par défaut.
      HttpOnlyLe cookie est invisible pour JavaScript: document.cookie ne le montre pas.Ne peut être posé que par le serveur. Indispensable pour les sessions : une faille XSS ne pourra pas voler l'identifiant.
    2. Une petite bibliothèque de fonctions

    3. Manipuler directement la chaîne document.cookie est source d'erreurs. Voici quatre fonctions réutilisables, cookies.js:

      // Petite bibliothèque pour lire et écrire des cookies
      
      function ecrireCookie(nom, valeur, options = {}) {
        const {
          jours = 30,
          chemin = "/",
          sameSite = "Lax",
          secure = location.protocol === "https:",
        } = options;
        let cookie = `${encodeURIComponent(nom)}=${encodeURIComponent(valeur)}`;
        cookie += `; max-age=${jours * 24 * 60 * 60}`;
        cookie += `; path=${chemin}`;
        cookie += `; SameSite=${sameSite}`;
        if (secure) {
          cookie += "; Secure";
        }
        document.cookie = cookie; // ajoute ou remplace UN cookie, n'efface pas les autres
      }
      
      function lireCookie(nom) {
        const prefixe = `${encodeURIComponent(nom)}=`;
        const trouve = document.cookie.split("; ").find((morceau) => morceau.startsWith(prefixe));
        return trouve ? decodeURIComponent(trouve.slice(prefixe.length)) : null;
      }
      
      function supprimerCookie(nom, chemin = "/") {
        // même nom et même chemin, avec une durée de vie nulle
        document.cookie = `${encodeURIComponent(nom)}=; max-age=0; path=${chemin}`;
      }
      
      function tousLesCookies() {
        if (document.cookie === "") {
          return {};
        }
        return Object.fromEntries(
          document.cookie.split("; ").map((morceau) => {
            const position = morceau.indexOf("=");
            return [
              decodeURIComponent(morceau.slice(0, position)),
              decodeURIComponent(morceau.slice(position + 1)),
            ];
          }),
        );
      }
    • lireCookie() découpe la chaîne sur "; " et cherche le morceau qui commence exactement par nom= (pour ne pas confondre theme et theme2).
    • Pour supprimer un cookie, il faut indiquer le même path qu'à sa création, sinon le navigateur considère qu'il s'agit d'un autre cookie.
  • Exemple complet : un bandeau de consentement

  • La page mémorise le prénom du visiteur dans un cookie, seulement s'il l'a accepté. Son choix est lui-même conservé dans un cookie consentement, pour ne pas lui reposer la question à chaque visite.

    index.html:

    <!doctype html>
    <html lang="fr">
      <head>
        <meta charset="utf-8" />
        <title>Bandeau de consentement</title>
        <link rel="stylesheet" href="style.css" />
        <script src="cookies.js" defer></script>
        <script src="consentement.js" defer></script>
      </head>
      <body>
        <h1>Centre de formation</h1>
        <p id="bonjour"></p>
        <label>
          Votre prénom :
          <input id="prenom" />
        </label>
        <button id="btn-memoriser" type="button">Mémoriser</button>
        <p><button id="btn-gerer" type="button">Gérer les cookies</button></p>
    
        <div id="bandeau" class="bandeau" hidden>
          <p>
            Ce site utilise un cookie pour mémoriser votre prénom. Aucune donnée n'est partagée avec des
            tiers.
          </p>
          <button id="btn-refuser" type="button">Refuser</button>
          <button id="btn-accepter" type="button">Accepter</button>
        </div>
      </body>
    </html>

    style.css:

    .bandeau {
      position: fixed;
      inset: auto 0 0 0;
      padding: 16px 24px;
      background: #1f2a3a;
      color: #fff;
      display: flex;
      gap: 12px;
      align-items: center;
    }
    
    .bandeau p {
      flex: 1;
      margin: 0;
    }
    
    /* sans cette règle, display: flex l'emporterait sur l'attribut hidden */
    .bandeau[hidden] {
      display: none;
    }

    consentement.js:

    const bandeau = document.getElementById("bandeau");
    const bonjour = document.getElementById("bonjour");
    
    function afficherBonjour() {
      const prenom = lireCookie("prenom");
      bonjour.textContent = prenom ? `Bon retour parmi nous, ${prenom} !` : "Bienvenue !";
    }
    
    function choisir(accepte) {
      // le choix lui-même est mémorisé 6 mois, qu'il soit positif ou négatif
      ecrireCookie("consentement", accepte ? "oui" : "non", { jours: 182 });
      if (!accepte) {
        supprimerCookie("prenom");
      }
      bandeau.hidden = true;
      afficherBonjour();
    }
    
    document.getElementById("btn-accepter").addEventListener("click", () => choisir(true));
    document.getElementById("btn-refuser").addEventListener("click", () => choisir(false));
    document.getElementById("btn-gerer").addEventListener("click", () => (bandeau.hidden = false));
    
    document.getElementById("btn-memoriser").addEventListener("click", () => {
      const prenom = document.getElementById("prenom").value.trim();
      if (lireCookie("consentement") !== "oui") {
        bandeau.hidden = false; // on redemande l'accord avant de déposer le cookie
        return;
      }
      if (prenom) {
        ecrireCookie("prenom", prenom, { jours: 30 });
        afficherBonjour();
      }
    });
    
    bandeau.hidden = lireCookie("consentement") !== null;
    afficherBonjour();
    • Le refus doit être aussi simple que l'acceptation : deux boutons de même importance, et un bouton « Gérer les cookies » pour changer d'avis.
    • En cas de refus, on supprime le cookie prenom déjà déposé.
    • Remarquez la règle .bandeau[hidden]: un display: flex écrit en CSS l'emporte sur l'attribut hidden, piège très courant.
  • Cookies et loi

    • En Europe, le RGPD et la directive ePrivacy imposent de demander l'accord de l'internaute avant de déposer des cookies qui ne sont pas strictement nécessaires (publicité, mesure d'audience non anonyme, réseaux sociaux). Les cookies indispensables (session, panier, mémorisation du choix de consentement) en sont dispensés.
    • En Tunisie, la loi organique n° 2004-63 sur la protection des données personnelles, contrôlée par l'INPDP, impose elle aussi d'informer les personnes et de recueillir leur consentement.
    • Bonnes pratiques : expliquer clairement à quoi sert chaque cookie, permettre de refuser aussi facilement que d'accepter, et redemander l'accord après quelques mois.
    • Cookies tiers : Safari, Firefox et Brave les bloquent déjà par défaut. Google, qui prévoyait depuis 2019 de les supprimer de Chrome, a renoncé: le 22 avril 2025, il a confirmé que Chrome les garderait, l'utilisateur pouvant les bloquer dans ses paramètres de confidentialité, et les API qui devaient les remplacer (Privacy Sandbox) ont été retirées en octobre 2025. Ce choix ne change rien aux obligations de consentement, qui viennent de la loi et non du navigateur.
    • Cookie Store API : une API moderne, asynchrone (avec des promesses), utilisable aussi dans les Service Workers. Elle est disponible dans tous les navigateurs récents (Baseline) depuis juin 2025 : Chrome 87, Safari 18.4 et Firefox 140. Comme les autres API récentes, elle exige un contexte sécurisé (HTTPS ou localhost).
    // La même chose avec la Cookie Store API (asynchrone, HTTPS ou localhost)
    await cookieStore.set({
      name: "theme",
      value: "sombre",
      expires: Date.now() + 365 * 24 * 60 * 60 * 1000, // en millisecondes
      sameSite: "lax",
    });
    
    const cookie = await cookieStore.get("theme"); // { name: "theme", value: "sombre", ... } ou null
    console.log(cookie?.value);
    
    await cookieStore.delete("theme");
    
    // Être prévenu de chaque changement de cookie
    cookieStore.addEventListener("change", (event) => {
      for (const modifie of event.changed) {
        console.log("modifié :", modifie.name, modifie.value);
      }
      for (const supprime of event.deleted) {
        console.log("supprimé :", supprime.name);
      }
    });
    • Plus besoin de découper une chaîne ni de calculer max-age: get(), set() et delete() font le travail, et l'événement change signale toute modification. Gardez document.cookie pour les navigateurs anciens.
  • Cookies ou autre chose ?

    • Utilisez un cookie quand le serveur a besoin de la donnée à chaque requête : session, langue ou thème choisi pour générer la page dans le bon style dès son envoi.
    • Pour des données qui ne servent qu'à JavaScript (une liste de tâches, un brouillon), préférez le localStorage: plus de place, une API plus simple, et rien n'est envoyé au serveur (leçon suivante).
    • Ne stockez jamais de mot de passe ni de donnée sensible dans un cookie lisible par JavaScript.
  • Activités

  • Activité 1 : explorer les cookies

    • Ouvrez un site d'information, puis DevTools → Application → Cookies. Combien de cookies voyez-vous ? Combien appartiennent à d'autres domaines (cookies tiers) ?
    • Repérez un cookie marqué HttpOnly. Tapez document.cookie dans la console : apparaît-il ?

    Activité 2 : le bandeau de consentement

    • Dans un dépôt GitHub js-stockage-navigateur, dossier cookies, reproduisez l'exemple complet et testez-le avec Live Server.
    • Vérifiez dans DevTools la date d'expiration des cookies prenom et consentement.
    • Ajoutez une liste déroulante « Langue » (français, anglais, arabe) mémorisée dans un cookie langue, et affichez le message d'accueil dans la langue choisie.

    Activité 3 : compteur de visites

    • Avec un cookie visites (durée : 1 an), affichez « C'est votre 1re visite », puis « C'est votre 5e visite »…
    • Ajoutez un cookie derniere qui mémorise la date de la dernière visite et affichez « Dernière visite : il y a 3 jours ».

    Activité 4 : questions

    • Que se passe-t-il si l'on écrit document.cookie = "a=1" puis document.cookie = "b=2"? Que contient document.cookie?
    • Pourquoi un identifiant de session doit-il être HttpOnly?
    • Quelle est la durée de vie d'un cookie créé sans max-age ni expires?
    • Pourquoi est-il déconseillé de stocker une liste de 200 tâches dans un cookie ?
    Corrigés. Activité 4 : document.cookie vaut "a=1; b=2", car chaque affectation ajoute ou remplace un seul cookie ; avec HttpOnly, un script injecté par une faille XSS ne peut pas lire l'identifiant et usurper la session ; c'est un cookie de session, supprimé à la fermeture du navigateur ; un cookie est limité à environ 4 Ko et il est renvoyé au serveur à chaque requête, ce qui alourdit inutilement les échanges : le localStorage est fait pour cela. Activité 3 : const visites = Number(lireCookie("visites") ?? 0) + 1; puis ecrireCookie("visites", visites, { jours: 365 });.
  • À retenir

    • Un cookie est un petit texte nom=valeur renvoyé au serveur à chaque requête.
    • document.cookie = "nom=valeur; max-age=…; path=/; SameSite=Lax" ajoute ou remplace un cookie ; max-age=0 le supprime.
    • Encodez les valeurs avec encodeURIComponent(); utilisez Secure et SameSite; les sessions sont en HttpOnly, posées par le serveur.
    • Consentement obligatoire pour les cookies non indispensables ; la Cookie Store API (Baseline depuis 2025) modernise leur manipulation.

    Sources : MDN Web Docs, web.dev, CNIL, INPDP.