¿Qué es JWT (JSON Web Token)? Autenticación Stateless Explicada
JWT es un estándar abierto para transmitir claims entre partes como un objeto JSON compacto y firmado — la base de la autenticación stateless en APIs, microservicios y sistemas de single sign-on.
Resumen JWT (JSON Web Token) es un estándar abierto (RFC 7519) que codifica claims — afirmaciones sobre un usuario o entidad — en una cadena compacta y URL-safe que puede ser firmada criptográficamente y verificada. Un JWT tiene tres partes: header, payload y signature. Cuando un usuario se autentica, el servidor emite un JWT que el cliente envía con cada solicitud posterior. El servidor verifica la firma sin consultar una base de datos, habilitando la autenticación stateless. Los access tokens JWT deben expirar en 5–60 minutos. Los refresh tokens gestionan las sesiones de larga duración.
¿Qué es JWT?
JWT (JSON Web Token) es un estándar abierto (RFC 7519) para transmitir información de forma segura entre partes como un objeto JSON compacto y URL-safe. Un JWT codifica claims — afirmaciones sobre una entidad (típicamente un usuario) — y está firmado criptográficamente para que el receptor pueda verificar su autenticidad e integridad sin contactar al emisor.
JWT resuelve un problema específico: cómo pasar información de identidad verificada entre servicios en un sistema stateless sin almacenar datos de sesión en el servidor.
Cómo funciona JWT
- El usuario se autentica — El cliente envía credenciales (usuario + contraseña) al servidor de autenticación.
- El servidor emite el JWT — El servidor valida las credenciales, crea un JWT con las claims del usuario (ID de usuario, roles, expiración), lo firma con un secreto o clave privada y lo devuelve.
- El cliente almacena y envía el JWT — El cliente guarda el JWT (típicamente en una cookie HttpOnly o en memoria) y lo envía en el header
Authorization: Bearer <token>con cada solicitud. - El servidor verifica el JWT — El servidor comprueba la firma, valida la expiración y las claims, y procesa la solicitud — sin necesidad de consultar la base de datos.
Este flujo es stateless: el servidor no mantiene datos de sesión. Cualquier instancia de servidor que conozca la clave de firma puede verificar el token.
Estructura de JWT: tres partes
Un JWT está formado por tres segmentos codificados en Base64URL separados por puntos: header.payload.signature
Header
{ "alg": "HS256", "typ": "JWT"}Especifica el algoritmo de firma (HS256, RS256, ES256) y el tipo de token. Codificado en Base64URL.
Payload
{ "sub": "user_123", "name": "María García", "role": "admin", "iat": 1712345678, "exp": 1712349278}Contiene las claims. Claims registradas (definidas por RFC 7519):
| Claim | Nombre | Descripción |
|---|---|---|
sub | Subject | Identificador único de la entidad (ID de usuario) |
iss | Issuer | Servicio que emitió el token |
aud | Audience | Destinatario(s) previsto(s) del token |
exp | Expiration | Timestamp Unix después del cual el token es inválido |
iat | Issued At | Timestamp Unix de cuándo se creó el token |
nbf | Not Before | Timestamp Unix antes del cual el token es inválido |
Los payloads JWT están codificados en Base64URL, no cifrados. Cualquier persona que intercepte un JWT puede decodificar y leer el payload. Nunca almacenes contraseñas, números de tarjeta de crédito ni datos personales (PII) en las claims JWT.
Signature
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)La firma garantiza que el token no ha sido manipulado. El servidor la verifica usando el mismo secreto (HMAC) o la clave pública del emisor (RSA/ECDSA).
Algoritmos de firma: HMAC vs RSA
| Algoritmo | Tipo | Clave | Usar cuando |
|---|---|---|---|
HS256 | Simétrico (HMAC) | Secreto compartido | Servicio único; emisor y verificador comparten el secreto |
RS256 | Asimétrico (RSA) | Par de clave pública/privada | Múltiples servicios; el emisor firma con clave privada, cualquier servicio verifica con clave pública |
ES256 | Asimétrico (ECDSA) | Par de clave pública/privada | Igual que RS256, con claves más pequeñas y mejor rendimiento |
Usa HS256 para autenticación simple en servicio único. Usa RS256 o ES256 cuando múltiples servicios independientes necesiten verificar tokens sin acceso al secreto de firma.
Access tokens vs refresh tokens
| Access token | Refresh token | |
|---|---|---|
| Propósito | Autoriza el acceso a la API | Obtiene nuevos access tokens |
| Tiempo de vida | Corto: 5–60 minutos | Largo: horas a semanas |
| Se envía con | Cada solicitud a la API | Solo en el endpoint de renovación del token |
| Almacenamiento | Memoria o cookie HttpOnly | Cookie HttpOnly segura |
| Revocable | No sin infraestructura adicional | Sí, mediante base de datos de tokens |
Los access tokens de corta duración limitan el daño en caso de robo del token. Los refresh tokens habilitan sesiones largas sin requerir que el usuario se autentique de nuevo.
JWT vs sesiones del lado del servidor
| JWT | Sesión del lado del servidor | |
|---|---|---|
| Estado | Stateless — sin almacenamiento en el servidor | Stateful — sesión almacenada en el servidor |
| Escalabilidad | Cualquier servidor verifica cualquier token | Requiere sticky sessions o session store compartido |
| Revocación | No se puede revocar antes de expirar sin blacklist | Revocación inmediata al eliminar la sesión |
| Tamaño | Mayor (token en cada solicitud) | Pequeño (solo session ID en cookie) |
| Mejor para | APIs, microservicios, SSO, apps móviles | Aplicaciones web que requieren cierre de sesión inmediato |
Errores comunes de seguridad con JWT
| Error | Riesgo | Corrección |
|---|---|---|
| Almacenar PII en el payload | Cualquiera puede decodificar el payload | Almacena solo claims no sensibles (ID de usuario, roles) |
| Access tokens de larga duración (horas/días) | El robo del token tiene una larga ventana de exposición | Establece exp en 5–60 minutos |
No validar la claim alg | Ataques de confusión de algoritmo (ej.: cambio RS256 → HS256) | Siempre impone el algoritmo esperado en el servidor |
Almacenar JWT en localStorage | Los ataques XSS pueden robar el token | Usa cookies HttpOnly, Secure, SameSite=Strict |
| Sin plan de revocación de token | Los tokens comprometidos siguen siendo válidos hasta expirar | Implementa expiración corta + rotación de refresh token |
No validar iss y aud | Se aceptan tokens de otros servicios | Siempre valida las claims de emisor y audiencia |
Cuándo usar JWT
Usa JWT cuando necesites:
- Autenticación stateless para APIs REST o GraphQL
- Single Sign-On (SSO) entre múltiples aplicaciones o dominios
- Claims de autorización embebidas en el token (roles, ámbitos, permisos)
- Apps móviles o SPAs que no pueden mantener sesiones del lado del servidor
- Autenticación servicio a servicio en microservicios
No uses JWT cuando necesites:
- Revocación inmediata de sesión (ej.: el cierre de sesión debe bloquear todas las solicitudes instantáneamente)
- Registro en el servidor de cada acción del usuario con contexto de sesión
- Tokens mayores de ~8KB (la sobrecarga de ancho de banda crece con cada solicitud)
Preguntas frecuentes
¿Qué es JWT en términos simples? JWT es un token que prueba quién eres y qué tienes permitido hacer. El servidor lo crea, lo firma criptográficamente y te lo entrega. Tú lo envías con cada solicitud. El servidor verifica la firma sin necesidad de consultarte en una base de datos.
¿Es JWT seguro? JWT es seguro cuando se usa correctamente. La firma previene la manipulación. Sin embargo, el payload solo está codificado en Base64 — no cifrado — por lo que cualquier persona que obtenga el token puede leer su contenido. Usa HTTPS para toda transmisión de tokens y nunca pongas datos sensibles en el payload.
¿Cuál es la diferencia entre JWT y OAuth? OAuth 2.0 es un framework de autorización que define cómo se emiten y usan los tokens. JWT es un formato de token. OAuth 2.0 comúnmente usa JWT como formato de access token, pero JWT puede usarse independientemente de OAuth.
¿Cómo invalido un JWT antes de que expire? Los JWTs no pueden invalidarse sin infraestructura adicional. Opciones: (1) usa tiempos de expiración cortos (5–15 minutos), (2) mantén una blacklist de tokens en un caché (Redis), (3) usa una claim de versión en el payload que se vuelve inválida cuando el usuario cambia su contraseña o cierra sesión.
¿Cuál es la diferencia entre HS256 y RS256? HS256 usa un secreto compartido único — tanto el emisor como cualquier verificador deben conocerlo. RS256 usa un par de claves pública/privada — el emisor firma con la clave privada, y cualquier verificador puede confirmar con la clave pública sin acceso al secreto. Usa RS256 cuando múltiples servicios independientes necesiten verificar tokens.
¿Debo almacenar el JWT en localStorage o en cookies? Almacena el JWT en cookies HttpOnly, Secure, SameSite=Strict. localStorage es accesible vía JavaScript y vulnerable a ataques XSS. Las cookies HttpOnly impiden completamente el acceso vía JavaScript. Las cookies requieren protección contra CSRF, pero este es un trade-off manejable.
¿Qué ocurre cuando un JWT expira? Cuando la claim exp de un JWT está en el pasado, el servidor lo rechaza con una respuesta 401 Unauthorized. El cliente debe usar un refresh token para obtener un nuevo access token, o solicitar al usuario que se autentique de nuevo.
¿Qué es una claim JWT? Una claim es una afirmación sobre el sujeto del token. Por ejemplo, "sub": "user_123" afirma que el sujeto del token es el usuario 123. "role": "admin" afirma que ese usuario es administrador. Las claims están definidas por RFC 7519 (claims registradas) o por la aplicación (claims privadas).