Definición
Los JWT / JWS / JWE forman una familia de estándares IETF (RFC 7515 a 7519, 2015) que define un formato compacto, URL-safe y portable para transportar claims (aserciones) firmados o cifrados en formato JSON.
Es la pieza fundamental de la autenticación moderna (access tokens OAuth, ID Tokens OIDC), de la firma a nivel de aplicación y del transporte seguro de datos estructurados (webhooks firmados, atestaciones).
| Estándar | RFC | Función |
|---|---|---|
| JWT | 7519 | Formato general (claims JSON codificados) |
| JWS | 7515 | Firma (integridad, autenticidad) |
| JWE | 7516 | Cifrado (confidencialidad) |
| JWA | 7518 | Algoritmos (HS256, RS256, A256GCM…) |
| JWK | 7517 | Representación de las claves en JSON |
Formato JWT (firmado = JWS)
Tres partes separadas por puntos:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNzE0MDAwMDAwfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c- Header (base64url):
{"alg":"HS256","typ":"JWT"} - Payload (base64url):
{"sub":"1234567890","name":"Alice","iat":1714000000} - Firma: HMAC o RSA/ECDSA según el
alg
Los claims estándar: iss (emisor), sub (sujeto), aud (destinatario), exp (expiración), nbf (not before), iat (issued at), jti (identificador único anti-replay), además de claims privados (email, roles, scope).
Algoritmos de firma (JWS)
| Algo | Tipo | Uso típico |
|---|---|---|
HS256 | HMAC simétrico | Pruebas, monolitos |
RS256 | RSA asimétrico | OAuth, OIDC clásico |
PS256 | RSA-PSS | Recomendado para FAPI (Open Banking) |
ES256 | ECDSA P-256 | Recomendado para FAPI, móvil |
EdDSA | Ed25519 | Moderno, rápido |
none | Sin firma | Prohibido (fallo histórico) |
Buenas prácticas: preferir el asimétrico (clave pública compartible) para las API públicas, priorizar PS256/ES256, no aceptar nunca alg: none y verificar siempre el alg esperado en el servidor en lugar de confiar en el header.
JWE (cifrado)
JWE cifra el payload (confidencialidad) además de la integridad, en 5 partes: header.encrypted_key.iv.ciphertext.tag. Key encryption común: RSA-OAEP, ECDH-ES, A256KW; content encryption: A256GCM, A128CBC-HS256. Uso: transporte de datos secretos (tarjeta tokenizada, datos de KYC) entre servicios.
JWT vs sesión tradicional
| Aspecto | Cookie de sesión | JWT |
|---|---|---|
| Estado | Servidor | Cliente (stateless) |
| Escalado | Sticky session o BD compartida | Trivial |
| Revocación | Eliminación en el servidor | Difícil (blacklist) |
| Legibilidad | Opaco | Legible (base64url) |
| Riesgo de robo | Cookie httpOnly | Bearer = portador |
Casos de uso
- OAuth / OIDC: access token (a menudo JWT; FAPI exige un JWT firmado y vinculado), ID Token (siempre JWT firmado), Request Object JAR (JWT firmado).
- API: un bearer JWT en
Authorization, verificado mediante la clave pública (endpoint JWKS). - Webhooks: Stripe, GitHub y Slack firman en JWS.
- Identidad / KYC: Verifiable Credentials de la W3C y SD-JWT (divulgación selectiva) para el EUDI Wallet.
- eIDAS: JAdES, perfil de firma cualificada basado en JWS.
Ataques conocidos
alg: none: algunas bibliotecas antiguas aceptaban un payload no verificado.- Confusión de algoritmo (HS256 vs RS256): firmar con la clave pública RSA como secreto HMAC, si el servidor no fija el
alg. - Inyección de
kid: unkidmal validado puede abrir una SQL injection o un path traversal. - Replay: un JWT robado sigue siendo válido hasta
exp(mitigación:jti+ caché, tokens cortos). - Fuga de información: el payload es legible — no poner en él ningún dato sensible, cifrar en JWE si hace falta.
Buenas prácticas
Preferir PS256/ES256, tokens cortos (5-15 min, refresh largo), tokens vinculados al cliente (mTLS, DPoP) en FAPI; verificar sistemáticamente iss, aud, exp, nbf y alg; rotar las claves (JWKS); evitar las PII en claro (JWE si es necesario); auditar con regularidad las dependencias (CVE).
Lo que JWT / JWS / JWE no es
- No es un cifrado de transporte: es a nivel de aplicación, TLS sigue siendo necesario.
- No es una sesión: un token, generalmente corto y stateless.
- No es una contraseña: un token de acceso emitido tras la autenticación.
- No es revocable de forma nativa: válido hasta la expiración, salvo blacklist mantenida.
En el ecosistema PSD2 / Open Finance
JWT y JWS están por todas partes: access tokens OAuth en la PSD2, ID Tokens OIDC (FranceConnect, EUDI Wallet), Request Objects JAR en FAPI, webhooks firmados (Bridge, Tink, Plaid) y Verifiable Credentials EUDI en SD-JWT.
Ejemplos concretos
- Webhooks de Stripe: firmados en HMAC SHA-256, un formato cercano al JWS.
- Auth0, Okta, Cognito: emiten JWT.
- OBIE UK: access tokens e ID Tokens en JWT PS256.
- EUDI Wallet: credentials en SD-JWT (probar "mayor de edad" sin revelar la fecha de nacimiento).
- FranceConnect: ID Tokens JWT.
- Vulnerabilidad de 2018: el fallo de "confusión de algoritmo" corregido globalmente en las bibliotecas.
- Herramientas: jwt.io (debugger),
jose(JS), PyJWT, java-jwt, jose4j.