JWT en cookies httpOnly vs localStorage: cuál es más seguro
Mario Rojas
1 min de lectura

Cuando haces login necesitas guardar el token en algún sitio. Las dos opciones más comunes tienen riesgos distintos.
localStorage
localStorage.setItem("token", token);
fetch("/api/posts", { headers: { Authorization: `Bearer ${token}` } });
Ventaja: simple, funciona con cualquier backend. Problema: cualquier JavaScript de la página puede leerlo. Si un atacante logra inyectar un script (XSS), por ejemplo a través de una librería comprometida o un comentario mal sanitizado, se lleva tu token.
Cookie httpOnly
El servidor la crea y el navegador la envía sola en cada petición:
res.cookie("token", token, {
httpOnly: true, // JavaScript no puede leerla
secure: true, // solo por HTTPS
sameSite: "lax", // no se envía en peticiones de otros sitios
});
Ventaja: un XSS no puede robar el token.
Problema: al enviarse automáticamente, hay que protegerse de CSRF. sameSite: "lax" cubre la mayoría de los casos.
Comparación rápida
| localStorage | Cookie httpOnly | |
|---|---|---|
| Robo por XSS | Sí | No |
| Riesgo de CSRF | No | Mitigado con sameSite |
| Funciona entre dominios | Fácil | Requiere configurar CORS y cookies |
Un detalle importante
La cookie httpOnly no te hace inmune a XSS: el atacante no puede leer el token, pero sí puede hacer peticiones en tu nombre mientras estés en la página. La defensa real sigue siendo no permitir scripts inyectados.
Mi elección
Cookie httpOnly + sameSite: "lax" + expiración corta. Y si el frontend y el backend están en dominios distintos, un proxy (como los rewrites de Next.js) para que todo parezca del mismo origen.