Decodificar en un solo paso
Un JSON Web Token tiene este aspecto: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMifQ.firma, es decir, tres cadenas Base64url unidas por puntos. Todo JWT empieza por eyJ porque así se ven los caracteres {" en Base64.
Pega el token en la herramienta de abajo. Se acepta el prefijo Bearer copiado de una cabecera Authorization. Verás el header y el payload como JSON con formato, los claims exp, iat, nbf y auth_time como fechas en tu hora local con una indicación relativa, y una línea de estado que dice si el token ha caducado o todavía no es válido. Para comprobar la firma, escribe el secreto compartido o la clave pública en Secreto o clave pública (opcional).
Pruébalo aquí: Decodificador JWT
Abrir la herramienta completaLas tres partes de un JWT
- Header: un objeto JSON pequeño como {"alg":"HS256","typ":"JWT"}. alg indica el algoritmo de firma; kid, si aparece, identifica qué clave se usó, algo útil cuando el emisor rota sus claves.
- Payload: los claims, es decir, datos sobre el usuario y el token, como el ID de usuario, el emisor, la audiencia, los roles y la hora de caducidad. Cualquiera que tenga el token puede leerlos.
- Firma: se calcula sobre el header y el payload codificados con un secreto (HMAC) o una clave privada (RSA o curva elíptica). Demuestra que las dos primeras partes no se modificaron y que las emitió alguien que tiene la clave.
- Un token con cinco partes en lugar de tres es un JWE cifrado. Su payload no se puede leer sin la clave privada, y la herramienta te avisa si pegas uno.
Claims habituales y su significado
El estándar JWT (RFC 7519) registra algunos nombres cortos de claims. Las horas son valores NumericDate: segundos desde el 1 de enero de 1970 en UTC, no milisegundos. Confundirlos es un error clásico, por ejemplo comparar exp con Date.now() de JavaScript, que devuelve milisegundos.
| Claim | Nombre | Significado |
|---|---|---|
| iss | Issuer (emisor) | Quién creó el token, a menudo la URL del proveedor de identidad |
| sub | Subject (sujeto) | A quién se refiere el token, normalmente un ID de usuario |
| aud | Audience (audiencia) | Qué API o aplicación debe aceptarlo |
| exp | Expiration (caducidad) | A partir de este momento el token debe rechazarse |
| nbf | Not before (no antes de) | Antes de este momento el token aún no es válido |
| iat | Issued at (emitido) | Cuándo se creó el token |
| jti | JWT ID | ID único, para impedir que se reutilice o para revocarlo |
| auth_time | Hora de autenticación | Cuándo inició sesión realmente el usuario (OpenID Connect) |
Decodificar a mano o con código
Base64url no es igual que el Base64 estándar: usa guion y guion bajo en lugar de + y /, y elimina el relleno =. La mayoría de los fallos al decodificar vienen de pasar una parte del JWT directamente a un decodificador Base64 estándar. Cambia el guion por + y el guion bajo por /, añade = hasta que la longitud sea múltiplo de 4 y después decodifica.
En Python, base64.urlsafe_b64decode(parte + "==") se ocupa del alfabeto y tolera el relleno de más. En la consola del navegador, atob funciona después de cambiar esos dos caracteres, pero devuelve los bytes como Latin 1, así que nombres como José o Muñoz en el payload necesitan un TextDecoder para verse bien en UTF-8. Bibliotecas como PyJWT, jsonwebtoken para Node.js o System.IdentityModel.Tokens.Jwt para .NET decodifican y verifican en una sola llamada; en producción usa su función de verificación, no un atajo que solo decodifica.
Para echar un vistazo rápido, una herramienta es más ágil y evita dejar el token en el historial de la terminal.
Decodificar no es verificar
Leer el payload te dice lo que el token afirma, no demuestra que sea cierto. Cualquiera puede crear un token con "role": "admin" y codificarlo en Base64. Solo una firma válida, comprobada con la clave correcta, hace fiable el contenido. Los servidores deben verificar siempre antes de usar cualquier claim.
En la herramienta, los tokens HS256, HS384 y HS512 se verifican con el secreto compartido. Los RS, PS y ES se verifican con la clave pública del emisor en formato PEM, el bloque que empieza con BEGIN PUBLIC KEY. Si tu proveedor de identidad solo publica las claves como una lista JWKS, convierte antes a PEM la que corresponde (la que tiene el mismo kid que el header). El resultado dice La firma es válida o La firma no coincide con la clave. Si pegas una clave privada, la herramienta te pide la pública.
Atento a estas señales de alarma: alg con valor none (el token no tiene firma y la herramienta lo marca como token sin firma), un algoritmo inesperado (un servidor que espera RS256 nunca debe aceptar un token HS256, es un ataque conocido) y tokens cuyo iss o aud no coinciden con tu sistema.
Problemas con tokens caducados o no válidos
- Caducado: revisa la fecha de caducidad en la sección Fechas. Los tokens de acceso suelen durar solo de 5 a 60 minutos a propósito; la aplicación debe usar un refresh token para obtener uno nuevo.
- Todavía no es válido: nbf o iat están en el futuro, lo que suele indicar que el reloj del servidor y el del emisor no coinciden. Muchas bibliotecas permiten un pequeño desfase de unos segundos a unos minutos; corrige el reloj con sincronización horaria.
- Esto no parece un JWT: el token está cortado, entre comillas o tiene espacios por la copia. Cópialo de nuevo desde la cabecera o la cookie original.
- No se pudo leer el header o el payload: falta parte del token. Los tokens largos suelen aparecer recortados en los logs.
- La firma no coincide: secreto equivocado, la clave pública de otro entorno (pruebas frente a producción), una clave rotada o un token manipulado.
Maneja los tokens con seguridad
Un token de acceso válido funciona como una contraseña hasta que caduca. No pegues tokens reales de producción en sitios web que los envían a un servidor, ni los pongas en tickets o chats. Este decodificador funciona por completo en tu navegador: el token no se envía, no se registra y no se guarda.
Si eres tú quien emite los tokens, mantén el payload pequeño y sin secretos. Como cualquiera puede leerlo, nunca metas en un JWT contraseñas, claves de API ni datos personales que el cliente no deba ver. Guarda el ID de usuario y los roles, y consulta el resto en el servidor.