JWT explicado: qué son, cómo funcionan y errores que no debes cometer
Guía completa de JSON Web Tokens: estructura, claims, firma, verificación, y los ataques históricos que has de conocer para no repetirlos.
Qué es un JWT
Un JSON Web Token (RFC 7519) es un formato compacto de tokens autocontenidos. Su gracia: el propio token contiene la información del usuario (claims), firmada criptográficamente. El servidor no necesita consultar una tabla de sesiones para validarlo: le basta verificar la firma.
Un JWT es una cadena con tres partes separadas por puntos:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGljZSIsImV4cCI6MTcxOTY3OTQwMH0.SIGNATURE
- Header — Base64URL de
{"alg":"HS256","typ":"JWT"} - Payload — Base64URL del JSON con claims
- Firma — HMAC-SHA256 (o RSA/ECDSA) sobre
header.payload
Decodifica cualquier JWT con nuestro decoder JWT para inspeccionar claims sin código.
Claims estándar (registered claims)
RFC 7519 define un conjunto pequeño de claims con significado universal:
iss(issuer) — quién emitió el tokensub(subject) — el usuario/entidadaud(audience) — para quién esexp(expiration) — timestamp Unix de caducidadnbf(not before) — no válido antes de este timestampiat(issued at) — cuándo se emitiójti(JWT ID) — identificador único para revocación
Además tú puedes añadir claims propios (role, email, plan), llamados private claims.
Firma: HS vs RS/ES
- HS256 / HS384 / HS512 — HMAC con clave simétrica. Rápido, sencillo. El servicio que emite y el que verifica comparten la clave. Bien para monolitos.
- RS256 / RS384 / RS512 — RSA asimétrico. El emisor firma con clave privada, cualquiera verifica con la pública. Ideal para federación (Google, Auth0, Cognito).
- ES256 / ES384 — ECDSA. Como RSA pero claves y firmas más cortas. Mejor opción moderna para federación.
Regla: si tienes más de un servicio verificando y no confías todos con la clave secreta, usa RS/ES.
Verificación correcta en el backend
Nunca aceptes un token sin verificar TODO esto:
1. Firma — con la clave correcta y algoritmo esperado. 2. exp — no expirado (con un pequeño clock skew, típicamente 30-60s). 3. nbf — ya activo. 4. iss — de un emisor de confianza (whitelist). 5. aud — dirigido a tu API.
Bibliotecas como jsonwebtoken (Node), pyjwt (Python), jose (Java) hacen todo esto si les pasas los parámetros correctos:
const decoded = jwt.verify(token, SECRET, {
algorithms: ['HS256'], // whitelist explícita
issuer: 'https://auth.miapp',
audience: 'https://api.miapp',
});
Los ataques históricos que debes conocer
1. alg: none
En 2015 se descubrió que bibliotecas populares aceptaban tokens con {"alg":"none"} y sin firma como válidos. Cualquiera podía forjar un token. Mitigación: pasa siempre algorithms explícito a la función de verify.
2. Confusión de algoritmos (HS256 vs RS256)
Si tu servidor espera RS256 pero acepta el algoritmo del header, un atacante puede firmar un token con HS256 usando la clave pública como clave HMAC. Como la clave pública es pública, el atacante forja tokens válidos. Mitigación: whitelist explícita de algoritmos.
3. Tokens sin expiración
Un JWT sin exp es válido para siempre. Si se filtra, no puedes revocarlo (los JWT son stateless por diseño). Mitigación: exp corto (5-15 min) + refresh tokens rotativos.
4. Datos sensibles en el payload
El payload es Base64, no cifrado. Cualquiera con el token lee su contenido. Nunca metas contraseñas, PII sensible ni secretos.
5. Tokens en localStorage
localStorage es accesible por cualquier JS del origen. Un XSS roba tus tokens al instante. Mitigación: guarda el refresh token en cookie httpOnly + Secure + SameSite=Strict; el access token en memoria del cliente.
Revocación: el punto débil de JWT
Al ser stateless, no hay forma nativa de invalidar un JWT antes de exp. Estrategias:
- Expiración muy corta + refresh — límites el radio de daño a 5-15 min.
- Lista de revocación — cache Redis con TTL del
jtirevocado. Consulta en cada petición. - Rotación de firma — cambia la clave y todos los tokens quedan inválidos (nuclear).
- Encoding de versión en el JWT — bumpea la versión del usuario al hacer logout y rechaza tokens con versión antigua.
JWT vs sesiones tradicionales
- JWT — stateless, escalable horizontalmente sin sticky sessions, ideal en microservicios y móviles. Complicado revocar.
- Sesiones (cookie + tabla en Redis) — trivial revocar, fácil rotar, coste mínimo en la mayoría de apps.
Para muchas apps monolíticas, sesiones tradicionales son más simples y seguras. Usa JWT cuando la escala o la federación lo justifiquen.
Herramientas útiles
- Decoder JWT para inspeccionar payloads.
- Generator JWT para emitir tokens de test con HS256/384/512.
- HMAC generator para verificar firmas y construir integraciones custom.
Bien usados, los JWT son una herramienta poderosa. Mal usados, un rifle apuntando a tu pie. Verifica siempre firma, exp, iss y aud, y no metas cosas sensibles en el payload.
Herramientas relacionadas
Decodifica el header y payload de un JSON Web Token para inspeccionar claims.
Firma tokens JWT con HS256, HS384 o HS512 usando la Web Crypto API.
Firma mensajes con HMAC-SHA1/256/384/512 usando Web Crypto.
Calcula digests SHA-1, SHA-256, SHA-384 y SHA-512 en tu navegador.