Session signée

L'action de connexion pose un cookie signé par HMAC ; le chargeur vérifie la signature à chaque requête. Les valeurs altérées échouent à la comparaison en temps constant et le chargeur traite la requête comme anonyme. HttpOnly maintient le token hors de portée de JS.

Astuce
Le cookie Max-Age ne protège que le navigateur — un token copié depuis les DevTools reste valide jusqu'à son expiration. Ajoutez toujours une vérification de TTL côté serveur (iat + SESSION_TTL_SECS) comme le fait ce démo, et lisez SESSION_SECRET depuis les variables d'environnement plutôt qu'une constante.

Statut

src/app/examples/session/page.tsxTSX
// HMAC-signed cookie. Login action sets it; loader verifies the
// signature on every request before trusting the name; logout clears it.

import { createHmac, timingSafeEqual } from "node:crypto";

const SECRET = process.env.SESSION_SECRET!;

function sign(payload: string) {
  return createHmac("sha256", SECRET).update(payload).digest("base64url");
}

export async function loader({ request }: { request: Request }) {
  const cookie = request.headers.get("cookie") ?? "";
  const token = parseCookies(cookie)["demo_session_token"];
  if (!token) return { session: null };
  // verify signature, return null on tamper
  return { session: verify(token) };
}

export async function action({ request }: { request: Request }) {
  const form = await request.formData();
  const name = String(form.get("name") ?? "");
  return new Response(null, {
    status: 200,
    headers: { "set-cookie": "demo_session_token=" + sign(name) + "; HttpOnly" },
  });
}