Cookies seguras: getCookie, setCookie y deleteCookie
Debajo de las sesiones selladas viven las cookies crudas, y saber gobernarlas es saber dónde vive una credencial. SolidStart expone los helpers de vinxi —`getCookie`, `setCookie` y `deleteCookie`— que operan sobre el evento de la petición actual. Esta lección enseña a leerlas y escribirlas tanto desde funciones de servidor (con `getRequestEvent().nativeEvent`) como desde middleware (con `event.nativeEvent`), y disecciona los atributos que separan una cookie segura de una vulnerable: `httpOnly` contra el robo por XSS, `secure` para exigir HTTPS, `sameSite` contra el CSRF, y el prefijo `__Host-` como candado final.
Los tres helpers de vinxi/http
Los tres helpers reciben como primer argumento el evento nativo de h3 —el que representa la petición viva— y actúan sobre sus cabeceras Cookie y Set-Cookie. getCookie devuelve el valor o undefined; setCookie programa una cookie con sus opciones; deleteCookie emite una cookie ya caducada para que el navegador la olvide.
import { getCookie, setCookie, deleteCookie } from "vinxi/http";// getCookie(evento, nombre) -> string | undefined// setCookie(evento, nombre, valor, opciones)// deleteCookie(evento, nombre, opciones)La firma pide el evento porque una cookie no existe en el vacío: pertenece a una petición y a una respuesta concretas. De ahí que estos helpers, como las sesiones, solo tengan sentido en el servidor, donde esas cabeceras existen.
Los atributos que hacen segura una cookie
Escribir una cookie sin atributos es dejar una credencial a la intemperie. Cada opción cierra un vector de ataque distinto, y una cookie de autenticación seria los combina todos.
setCookie(evento, "token", valorFirmado, { httpOnly: true, // invisible a document.cookie: el XSS no puede robarla secure: true, // el navegador solo la envia por HTTPS sameSite: "lax", // no viaja en peticiones cross-site peligrosas: frena CSRF path: "/", // alcance: toda la app maxAge: 60 * 60 * 24 * 7, // vida en segundos; sin esto seria de sesion});httpOnlyla oculta del JavaScript de la página: aunque un atacante inyecte un script (XSS), no podrá leerdocument.cookiepara exfiltrar el token. Es la defensa número uno de cualquier credencial.secureprohíbe que la cookie viaje por HTTP en claro; sin ella, una red hostil la vería.sameSitecontrola si la cookie acompaña a peticiones iniciadas desde otro sitio.lax—valor por defecto sensato— la envía en navegaciones de nivel superior pero no en peticiones incrustadas;strictla retiene incluso al llegar desde un enlace externo;nonela manda siempre, pero obliga asecurey solo se usa en flujos cross-site legítimos.
Cookies desde funciones de servidor y desde middleware
El único matiz práctico es de dónde sacas el evento. En middleware ya lo tienes: event.nativeEvent. En una función de servidor lo recuperas con getRequestEvent de solid-js/web y accedes a su .nativeEvent.
// Desde una funcion de servidorimport { getRequestEvent } from "solid-js/web";import { getCookie, setCookie } from "vinxi/http";export async function fijarTema(tema: "claro" | "oscuro") { "use server"; const event = getRequestEvent()!; setCookie(event.nativeEvent, "tema", tema, { secure: true, sameSite: "lax", maxAge: 60 * 60 * 24 * 365, // un ano path: "/", // sin httpOnly: aqui si queremos que el cliente lea el tema });}export async function leerTema() { "use server"; const event = getRequestEvent()!; return getCookie(event.nativeEvent, "tema") ?? "claro";}// Desde middlewareimport { createMiddleware } from "@solidjs/start/middleware";import { getCookie } from "vinxi/http";export default createMiddleware({ onRequest: (event) => { const tema = getCookie(event.nativeEvent, "tema"); // ya tienes el evento event.locals.tema = tema ?? "claro"; },});Observa el contraste deliberado: la cookie de tema no lleva httpOnly, porque queremos que el cliente la lea para pintar sin parpadeo; la cookie de sesión de la lección anterior sí lo lleva, porque su valor es una credencial que el cliente nunca debe tocar. El atributo no es un adorno: codifica quién tiene derecho a leer.
El prefijo __Host- y el candado completo
Para una cookie de sesión, el endurecimiento máximo es nombrarla con el prefijo __Host-. El navegador solo acepta una cookie así si viene con secure, con path a la raíz y sin atributo domain, lo que la ata a un único host y la blinda contra ataques donde un subdominio comprometido fija cookies para el dominio padre. Es una garantía que el propio navegador hace cumplir.
setCookie(evento, "__Host-sesion", valorSellado, { httpOnly: true, secure: true, sameSite: "lax", path: "/", // obligatorio para __Host- // sin domain: obligatorio para __Host-});Para borrar una cookie, deleteCookie debe recibir los mismos path y domain con que se creó; si no coinciden, el navegador la trata como otra cookie distinta y la original sobrevive. Y distingue la cookie persistente —con maxAge o expires, que aguanta cierres del navegador, la que quieres para un «recuérdame»— de la cookie de sesión —sin ninguno de los dos, que muere al cerrar la pestaña, la adecuada para un acceso efímero—.