Decodificador JWT

Sustituye la entrada actual por datos de demostración.

Resultado esperado: La cabecera muestra HS256 y el contenido muestra sub = demo-user. La firma es inválida a propósito; no es un token de acceso.

Limitaciones: Decodificar no autentica el token. La verificación opcional admite HS256/384/512; la aplicación también debe validar emisor, destinatario y fechas.

Decodificar no es verificar. Cualquiera puede leer el payload de un JWT y cualquiera puede falsificar uno que decodifique sin errores — un token decodificado muestra lo que afirma, nunca si eso es cierto. Todo esto se ejecuta en tu navegador; tu token nunca se envía a ninguna parte.

Nada de lo que escribes aquí se almacena, registra ni comparte.

Pega un JWT para leer su cabecera y su payload y ver cuándo caduca. La decodificación ocurre íntegramente en tu navegador, así que el token nunca sale de tu dispositivo.

Cómo usarlo

  1. Pega el token en el campo de entrada.
  2. La cabecera, el payload y los claims de tiempo aparecen debajo.
  3. Opcionalmente, introduce el secreto para verificar una firma HS256 o HS512.

Cómo leer los tres segmentos

Un JWT son tres segmentos codificados en base64url unidos por puntos, y aquí el base64url se escribe sin relleno, por eso los segmentos no terminan en signos igual como ocurre con el base64 normal.

El primer segmento es la cabecera: un pequeño objeto JSON que indica el algoritmo de firma en alg, normalmente el tipo en typ y a veces un identificador de clave en kid, para que quien verifica sepa con cuál de varias claves comprobarlo. El segundo es el payload, un objeto JSON de claims. El tercero es la firma, que son bytes en bruto y no JSON, por eso aquí se muestra en hexadecimal.

La firma abarca los dos primeros segmentos exactamente como aparecen, unidos por un punto: el texto codificado, no el JSON que representa. Por eso un token no puede embellecerse, volver a serializarse ni reordenar sus claims sin quedar invalidado, y por eso el decodificador te muestra las claims pero trata el texto original como lo que de verdad importa.

Decodificar no es verificar

Es el punto en el que más se malinterpretan los JWT, así que conviene decirlo sin rodeos. El payload está codificado, no cifrado. Cualquiera que tenga el token puede leer todas sus claims. Y cualquiera puede construir un token cuyo payload diga lo que quiera, que se decodificará perfectamente aquí y en cualquier otro sitio.

Lo que te da un token decodificado es un conjunto de afirmaciones sin ninguna prueba. La prueba es la firma, y comprobarla requiere la clave. Hasta que se haga esa comprobación - con una clave elegida de antemano y un algoritmo elegido de antemano -, un token solo te dice lo que alguien quiere que creas.

En la práctica: nunca tomes una decisión de autorización a partir de un payload decodificado. Decodificar un token en un depurador para ver qué contiene está bien. Leer la claim sub en el código de la aplicación sin verificarla, porque el token pasó por una pasarela que supuestamente ya la comprobó, es como los servicios acaban confiando en identidades falsificadas. Esta página ofrece verificación HS256 opcional precisamente para que la diferencia se vea.

Las claims, y quién debe comprobarlas

La RFC 7519 registra siete claims. iss es el emisor, sub el sujeto al que se refiere el token, aud la audiencia a la que va destinado y jti un identificador único del propio token. Las tres claims de tiempo - exp, nbf e iat - son valores NumericDate en segundos desde la época Unix, no en milisegundos, que es el motivo más habitual por el que se rechaza un token hecho a mano.

Ninguna se aplica sola. Un token con un exp en el pasado está caducado solo porque un verificador lo compara con el reloj y lo rechaza. Un token emitido para otra audiencia solo es peligroso si nadie comprueba aud, y así es como un token creado para un servicio se reutiliza contra otro que comparte la misma clave de firma. La mayoría de bibliotecas comprueban exp por defecto y aud solo si les indicas qué esperar.

Es normal que haya pequeñas diferencias de reloj entre las máquinas que emiten y verifican, así que los verificadores suelen tolerar un desfase de uno o dos minutos. Esta página muestra cada claim de tiempo como una fecha legible e indica si el token está ahora dentro de su periodo de validez.

Cuándo un JWT no es la opción adecuada

Un JWT es un token portador que lleva sus propias claims, lo que lo hace excelente para llamadas sin estado entre servicios y torpe como mecanismo de sesión.

La torpeza está en la revocación. Como el verificador no necesita más que la clave, nunca consulta un almacén y, por tanto, no hay forma de invalidar un token antes de su exp. Cierra la sesión de un usuario, cambia su contraseña, desactiva su cuenta: cualquier token ya emitido seguirá funcionando hasta que caduque. Las soluciones habituales - vidas muy cortas con tokens de refresco, o una lista de denegación de valores jti consultada en cada petición - reintroducen el estado que se suponía que la ausencia de estado eliminaba.

También importa dónde se guardan. Un token en localStorage es legible por cualquier script que se ejecute en la página, así que un solo fallo de cross-site scripting basta para robarlo; una cookie httpOnly no, a cambio de necesitar protección CSRF. Y como viajan en una cabecera en cada petición, los payloads grandes tienen un coste real: mete suficientes claims y chocarás con el límite de tamaño de cabecera de algún proxy.

Para una sesión web normal, un identificador opaco aleatorio asociado a un almacén en el servidor es más sencillo, se revoca al instante y ocupa menos.

Qué hace la verificación, paso por paso

Una verificación correcta es una secuencia, y es justo donde se salta un paso donde viven los ataques conocidos. Primero, decide el algoritmo de antemano y rechaza cualquier token cuyo header no coincida: nunca leas el alg del token y confíes en él. Segundo, selecciona la clave: para un secreto compartido es una constante; para un token asimétrico es la clave pública que corresponde al kid del header, obtenida del endpoint JWKS del emisor y guardada en caché.

Tercero, recalcula la firma sobre los dos primeros segmentos tal como aparecen y compárala en tiempo constante. Cuarto, y solo después de que la firma sea válida, lee los claims: contrasta exp y nbf con el reloj con una tolerancia pequeña, comprueba que iss sea el emisor que esperas y que aud te incluya.

La mayoría de las bibliotecas hace todo esto si las configuras, y la mayoría de las vulnerabilidades surge de una aplicación que hace una parte a mano. Decodificar para leer un claim antes de verificar está bien en un depurador y es peligroso al atender una petición, porque en ese momento el token sigue siendo apenas una afirmación que alguien hizo.

Dónde encajan los JWT en OAuth y OpenID Connect

En OpenID Connect, el id_token es un JWT y está pensado para el cliente: dice quién inició sesión, cuándo y de qué manera. El access token es otra cosa, pensada para la API, y aunque muchos proveedores lo emiten como JWT, la especificación no lo exige: puede ser una cadena opaca que la API valida mediante introspección.

La distinción importa porque determina qué debe hacer tu API. Si el access token es opaco, la API llama al endpoint de introspección del proveedor; si es un JWT, la API lo verifica localmente contra las claves publicadas. Tratar un id_token como access token es un error de integración frecuente: fue emitido para otra audiencia, y una API que lo acepta terminará aceptando tokens emitidos para cualquier aplicación que atienda ese mismo proveedor.

Los scopes y los roles dentro de un token son afirmaciones del emisor, no permisos. La API sigue decidiendo qué puede hacer quien llama; el token solo dice quién es y por qué estuvo dispuesto a responder el emisor.

Las vulnerabilidades que se repiten una y otra vez

El truco de alg: none declara que un token no está firmado y hace una década varias bibliotecas lo aceptaban. La confusión de algoritmos es más sutil: toma un token RS256, cambia el header a HS256 y fírmalo usando la clave pública del emisor como secreto del HMAC; un verificador que lee el algoritmo del propio token lo aceptará, porque la clave pública no es un secreto.

Los secretos compartidos débiles son el hallazgo más común en la práctica. Un JWT contiene todo lo necesario para probar un secreto candidato sin conexión, a la velocidad que permita el hardware del atacante, así que una palabra de diccionario cae en segundos y permite a cualquiera emitir tokens con los claims que se le antojen.

Después están los errores de lógica: la falta de comprobación de aud, que deja que un token de un servicio autentique en otro que comparte la misma clave; parámetros kid usados para cargar una clave desde una ruta sin sanear la entrada; y tokens aceptados desde la cadena de consulta, donde acaban en los logs del servidor, en el historial del navegador y en las cabeceras referrer.

Sesiones o tokens para una aplicación web

Para una sola aplicación web con su propio backend, una sesión del lado del servidor con un identificador opaco en una cookie es más simple y mejor en casi todos los aspectos: la revocación es inmediata, la cookie es pequeña, el contenido nunca sale del servidor y no hay ninguna firma que se pueda equivocar. El costo es un almacén de sesiones, que para la mayoría de las aplicaciones es una tabla o una clave en Redis.

Los JWT se ganan su lugar cuando quien verifica no puede consultar al emisor: llamadas entre servicios que cruzan una frontera de confianza, una API usada por terceros o un borde sin estado que debe validar peticiones sin un viaje de ida y vuelta. Esas son restricciones reales y justifican la complejidad cuando existen.

El híbrido al que llega la mayoría de los equipos es un access token de vida corta, de minutos y no de horas, junto con un refresh token de vida más larga guardado en una cookie httpOnly y almacenado también en el servidor para poder revocarlo. Eso da verificación sin estado en el camino habitual y a la vez conserva un lugar donde decir que no.

Dónde guardar un token en el navegador

localStorage puede leerlo cualquier script que se ejecute en la página, así que una sola falla de cross-site scripting en cualquier punto del origen, incluido un script de analítica o de publicidad de terceros, filtra el token. Esta es la opción predeterminada en muchos tutoriales y es la más débil de las disponibles.

Una cookie httpOnly, Secure y con SameSite no puede ser leída por ningún script, lo que elimina esa clase de ataque e introduce la necesidad de protección contra CSRF, ya que el navegador adjunta la cookie automáticamente. SameSite=Lax cubre la mayor parte y un token antifalsificación cubre el resto.

Mantener el token solo en memoria, como una variable de la aplicación que se renueva al cargar la página mediante un endpoint autenticado por cookie, es el patrón común más fuerte y el menos cómodo, porque cada recarga exige un viaje de refresco. Elijas lo que elijas, el token igual viaja en una cabecera en cada petición, así que mantener el payload pequeño es una decisión de rendimiento además de una de privacidad.

Preguntas frecuentes

¿Decodificar un JWT me dice que es válido?
No, y esto es lo más importante que hay que entender sobre los JWT. El payload está codificado en base64url, no cifrado ni protegido: cualquiera puede leerlo, y cualquiera puede fabricar un token que decodifique perfectamente. Solo verificar la firma con la clave correcta demuestra que un token es auténtico y no ha sido alterado.
¿Es seguro pegar aquí un token real?
La decodificación y la verificación se ejecutan en JavaScript en esta página. No se sube, registra ni transmite nada. Aun así, trata cualquier JWT como una credencial viva: si se ha filtrado en otro sitio, revócalo en lugar de fiarte de dónde lo pegaste.
¿Por qué solo se pueden verificar HS256 y HS512?
Son simétricos: el mismo secreto firma y verifica, así que la comprobación puede ejecutarse localmente con lo que tú aportas. RS, ES y PS son asimétricos y necesitan la clave pública del emisor, normalmente obtenida de un endpoint JWKS, que es otra tarea distinta.
¿Qué significan exp, iat y nbf?
Son claims registrados que contienen un NumericDate, medido en segundos desde la época Unix y no en milisegundos. exp es cuándo deja de ser válido el token, iat cuándo se emitió y nbf el primer momento en que puede usarse. Esta herramienta muestra cada uno como una fecha legible.
¿Qué significa alg: none?
Declara un token sin firma. Las bibliotecas que lo aceptan pueden ser engañadas para admitir tokens falsificados, así que es un patrón de ataque conocido y cualquier verificador debería rechazarlo. Esta herramienta nunca marcará como verificado un token así.

Última actualización:

Referencias

RFC 7519 — JSON Web Token

Cambios recientes

  • — Se añadieron un ejemplo ejecutable, resultados esperados, limitaciones y referencias.

Informar de un problema

Incluye los pasos, el resultado esperado y el real. Elimina secretos y datos personales.

Herramientas relacionadas