Seguridad··11 min de lectura

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 token
  • sub (subject) — el usuario/entidad
  • aud (audience) — para quién es
  • exp (expiration) — timestamp Unix de caducidad
  • nbf (not before) — no válido antes de este timestamp
  • iat (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 jti revocado. 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

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

Sigue leyendo