Tokens JWT: ¿Qué Hay Dentro?
Ya los has visto — esas cadenas largas que empiezan con eyJ que aparecen en headers Authorization, cookies y local storage. Los JWTs (JSON Web Tokens) están en todas partes en la autenticación moderna, y entender su estructura es esencial para depurar problemas de auth.
Anatomía de un JWT
Un JWT tiene tres partes separadas por puntos:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|___________ header ___________|.|_____________ payload ______________|.|_________ signature __________|Cada parte es JSON codificado en Base64url (no cifrado — cualquier persona puede leerlo).
El Header
{
"alg": "HS256",
"typ": "JWT"
}Indica el algoritmo de firma. Valores comunes:
HS256— HMAC con SHA-256 (simétrico, usa un secreto compartido)RS256— RSA con SHA-256 (asimétrico, usa par de claves pública/privada)ES256— ECDSA con curva P-256 (asimétrico, claves más pequeñas)none— PELIGRO: sin firma. Nunca aceptes esto en producción.
El Payload (Claims)
{
"sub": "user-123",
"name": "Alice",
"email": "alice@example.com",
"role": "admin",
"iat": 1716239022,
"exp": 1716242622,
"iss": "auth.myapp.com"
}Claims estándar:
| Claim | Significado |
|---|---|
sub | Subject (ID del usuario) |
iat | Issued At (timestamp Unix) |
exp | Expiration (timestamp Unix) |
iss | Issuer (quién creó el token) |
aud | Audience (destinatario previsto) |
nbf | Not Before (válido después de este momento) |
Puedes agregar cualquier claim personalizado — solo no pongas datos sensibles, porque el payload es legible por cualquier persona que tenga el token.
La Firma
Esto es lo que hace que los JWTs sean a prueba de manipulación:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)Si alguien modifica el header o payload, la firma no coincidirá. El servidor rechaza el token. Pero la firma solo prueba integridad — no oculta el contenido.
Escenarios Comunes de Debug
"Token expired": Decodifica el token, verifica el claim exp. Convierte el timestamp Unix a fecha. ¿El reloj del servidor está desajustado? ¿El tiempo de vida del token es muy corto?
"Invalid signature": El token fue firmado con un secreto/clave diferente al que tu servidor espera. Común en setups multi-ambiente donde staging y producción usan secretos diferentes.
"Token malformed": El token no tiene tres partes separadas por punto, o la decodificación Base64 falla. Frecuentemente causado por truncamiento al copiar tokens.
Consideraciones de Seguridad
- No almacenes datos sensibles en el payload. Es codificado en Base64, no cifrado. Cualquier persona con el token puede leer los claims.
- Siempre verifica la firma en el servidor. Nunca confíes en un JWT sin verificación.
- Define tiempos de expiración razonables. Access tokens de corta duración (15-60 min) + refresh tokens de larga duración es el patrón estándar.
- Usa HTTPS. Los JWTs en tránsito pueden ser interceptados en conexiones no cifradas.
JWT en Código
// Node.js — verificar un token
import jwt from 'jsonwebtoken';
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log(decoded.sub); // ID del usuario
} catch (err) {
if (err.name === 'TokenExpiredError') {
// manejar refresh
}
}# Python
import jwt
try:
payload = jwt.decode(token, SECRET, algorithms=['HS256'])
print(payload['sub'])
except jwt.ExpiredSignatureError:
# manejar refresh
passDecodifica tu token ahora: Decodificador JWT — pega cualquier JWT, ve el header, payload y expiración instantáneamente. Ningún dato se envía a servidores.