JWT Tokens Explicados: Estructura, Seguridad y Errores Comunes
Descubre cómo funcionan los JSON Web Tokens, qué contienen y las trampas de seguridad que suelen afectar a los desarrolladores en producción.
Los JSON Web Tokens (JWTs) están en todas partes: impulsan la autenticación en SPAs, aplicaciones móviles y arquitecturas de microservicios en todo el mundo. Sin embargo, también son uno de los elementos de seguridad más malinterpretados en el desarrollo web. Implementarlos incorrectamente puede derivar en omisión de autenticación, escalada de privilegios o el robo total de una cuenta.
¿Qué es un JWT?
Un JWT es una cadena compacta y segura para URLs que codifica un conjunto de claims (afirmaciones) sobre un usuario o sesión. Tiene este aspecto:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Está compuesto por tres segmentos codificados en Base64URL separados por puntos:
- Header — algoritmo y tipo de token
- Payload — los claims (datos del usuario)
- Signature — prueba criptográfica de integridad
Pega cualquier JWT en nuestro JWT Decoder para inspeccionar las tres partes al instante, sin necesidad de recurrir a ningún servidor externo.
Anatomía de un JWT
Header
{
"alg": "HS256",
"typ": "JWT"
}
alg especifica el algoritmo de firma. Valores habituales:
HS256— HMAC con SHA-256 (simétrico, clave secreta única)RS256— RSA con SHA-256 (asimétrico, clave pública/privada)ES256— ECDSA con SHA-256 (asimétrico, claves más pequeñas)
Payload
{
"sub": "user_abc123",
"email": "alice@example.com",
"role": "admin",
"iat": 1711670400,
"exp": 1711756800
}
Claims estándar registrados:
| Claim | Significado |
|---|---|
sub |
Subject (sobre quién trata el token) |
iss |
Issuer (quién creó el token) |
aud |
Audience (quién debe aceptarlo) |
exp |
Tiempo de expiración (timestamp Unix) |
iat |
Emitido en (timestamp Unix) |
nbf |
Not before (no aceptar antes de este momento) |
Signature
Para HS256:
HMAC-SHA256(base64url(header) + "." + base64url(payload), secret)
La firma garantiza que el token no ha sido manipulado. El payload NO está cifrado — solo está codificado. Cualquiera puede leerlo.
Nunca almacenes datos sensibles como contraseñas o números de tarjeta de crédito en el payload de un JWT.
HS256 vs. RS256: ¿cuál elegir?
HS256 utiliza un único secreto compartido. Cada servicio que necesite verificar tokens debe tener el mismo secreto. Es sencillo en monolitos, pero peligroso en arquitecturas de múltiples servicios: si algún servicio se ve comprometido, un atacante puede falsificar tokens.
RS256 usa claves asimétricas. El servidor de autenticación firma con una clave privada; el resto de servicios verifican con la clave pública. Comprometer un servicio consumidor no le otorga al atacante la capacidad de falsificar tokens. Prefiere RS256 para cualquier sistema con múltiples servicios.
La vulnerabilidad alg: none
Uno de los ataques más conocidos contra JWTs. Algunas bibliotecas más antiguas aceptaban un token con "alg": "none" y sin firma, tratándolo como válido. Un atacante podía construir:
{ "alg": "none" }
con cualquier payload y eludir la autenticación por completo.
Solución: Especifica siempre de forma explícita los algoritmos permitidos en tu biblioteca de JWT. Nunca aceptes none.
// ❌ Peligroso
jwt.verify(token, secret);
// ✅ Seguro — solo acepta HS256
jwt.verify(token, secret, { algorithms: ["HS256"] });
Ataque de confusión de algoritmos
Otra vulnerabilidad crítica: si tu biblioteca detecta automáticamente el algoritmo a partir del header, un atacante puede cambiar RS256 por HS256 y firmar el token usando la clave pública como secreto HMAC (que es, por definición, pública).
Solución: Define siempre el algoritmo esperado de forma fija en el código. Nunca confíes en el header alg.
Almacenamiento de tokens: dónde guardar los JWTs
| Almacenamiento | Riesgo XSS | Riesgo CSRF | Notas |
|---|---|---|---|
localStorage |
Alto | Ninguno | Accesible para cualquier JS en la página |
sessionStorage |
Alto | Ninguno | Se borra al cerrar la pestaña |
| Cookie HTTP-only | Ninguno | Medio | Ideal para aplicaciones web; usa SameSite=Strict |
| Memoria (variable) | Bajo | Ninguno | Se pierde al recargar; para SPAs |
En aplicaciones web, las cookies HTTP-only con SameSite=Strict son la opción más segura. Para aplicaciones nativas, lo adecuado son las APIs de almacenamiento seguro (Keychain, Keystore).
Expiración y refresh tokens
El patrón estándar consiste en tokens de acceso de corta duración (5-15 minutos) combinados con refresh tokens de larga duración:
- El usuario inicia sesión → el servidor emite un access token (15 min) + un refresh token (7 días, almacenado en BD)
- El cliente utiliza el access token para las llamadas a la API
- Cuando el access token expira, el cliente envía el refresh token → recibe un nuevo access token
- Al cerrar sesión, se invalida el refresh token en la base de datos
Esto limita el daño potencial en caso de que un access token sea robado.
Revocar JWTs
Los JWTs son stateless: una vez emitidos, son válidos hasta su expiración. Esto implica una compensación. Opciones para revocarlos antes de tiempo:
- Lista de bloqueo — almacena los valores JTI (JWT ID) invalidados en Redis y compruébalos en cada solicitud.
- Expiración corta — tokens de 5 minutos reducen el radio de impacto.
- Rotación de refresh tokens — detecta la reutilización de un token rotado como señal de robo.
Depuración con el JWT Decoder
Al depurar problemas de autenticación, utiliza nuestro JWT Decoder para:
- Inspeccionar el payload completo sin escribir código
- Comprobar los timestamps de expiración en formato legible
- Verificar el algoritmo que se está utilizando
- Detectar claims inesperados o faltantes
Toda la decodificación ocurre localmente en tu navegador: los tokens nunca salen de tu máquina.
Lista de verificación de seguridad para JWTs
- Usa RS256 o ES256 para arquitecturas con múltiples servicios
- Especifica explícitamente los algoritmos permitidos en tu biblioteca
- Valida los claims
exp,issyauden cada solicitud - Almacena los tokens en cookies HTTP-only en aplicaciones web
- Usa tiempos de vida cortos para los access tokens (15 min o menos)
- Implementa rotación de refresh tokens con detección de reutilización
- Nunca incluyas datos sensibles en el payload
- Usa HTTPS en todas partes: un token en texto plano equivale a no tener autenticación
Los JWTs son potentes y prácticos, pero su seguridad depende por completo de cómo se implementen. Comprende la estructura, conoce los ataques y tu capa de autenticación será sólida.