En esta página
- TL;DR: ¿es seguro jwt.io?
- Lo que realmente sucede cuando pegas un JWT en un decodificador online
- El modelo de amenazas real
- Lo que han dicho los propios mantenedores de jwt.io
- Qué significa realmente “decodificador JWT del lado del cliente”
- Cómo verificar que una herramienta JWT es realmente del lado del cliente (receta de 60 segundos)
- Método 1: la prueba del modo avión
- Método 2: la auditoría de red en DevTools
- Método 3: lee la barra de URL
- Una alternativa privada a jwt.io: decodifica en tu navegador
- Verificar firmas sin exponer tu secreto
- HMAC (HS256/HS384/HS512)
- RSA / ECDSA (RS256, RS384, RS512, ES256, ES384, ES512)
- Decodificar un JWT localmente con la CLI
- Cómo compartir un JWT con seguridad en un informe de bug
- Preguntas frecuentes
- ¿Es jwt.io de código abierto?
- ¿Ha filtrado jwt.io tokens alguna vez?
- ¿Puedo autoalojar jwt.io?
- ¿Decodificar un JWT requiere el secreto?
- ¿Por qué mi token aparece como expirado aunque acabo de acuñarlo?
- ¿Es realmente seguro pegar un token en una herramienta que has verificado que es del lado del cliente?
- ¿Cómo se relaciona esto con la postura de privacidad más amplia de remove.sh?
- En resumen
Por qué no deberías pegar JWTs en jwt.io (y qué usar en su lugar)
Un token de producción aparece en tu terminal. Necesitas saber quién lo emitió, cuándo expira y qué claims contiene, y rápido. Así que haces lo que hace la mayoría de los desarrolladores: abres jwt.io, pegas el token y lees el payload decodificado.
Detente. Ese JWT es una credencial. El sitio en el que acabas de pegarlo lo opera un tercero, con un historial de analíticas añadidas silenciosamente y una reescritura en curso impulsada por las propias preocupaciones de privacidad de sus mantenedores. Hay una respuesta mejor, y la consulta de búsqueda que probablemente te trajo aquí, “alternativa privada a jwt.io”, tiene una respuesta real.
Esta guía recorre el modelo de amenazas real, lo que el propio equipo de jwt.io ha reconocido públicamente y cómo verificar que un depurador de JWT nunca envía tu token a ningún sitio. Si prefieres saltarte la explicación y decodificar un token ahora mismo en tu navegador, el JWT Decoder es totalmente del lado del cliente: ábrelo, desconéctate de internet y verás que sigue funcionando.
TL;DR: ¿es seguro jwt.io?
Respuesta corta: la propia página principal de jwt.io te advierte. Su propio texto de aviso dice, en esencia, “los JWTs son credenciales: ten cuidado dónde los pegas”. Esa advertencia es correcta y se aplica a jwt.io tanto como a cualquier otra herramienta online.
Para tokens de demostración no sensibles, jwt.io está bien. Para cualquier cosa de un entorno real (producción, staging, sandbox, integración con un partner), asume el valor por defecto más seguro: decodifica localmente. El resto de este artículo es el porqué y el cómo.
Lo que realmente sucede cuando pegas un JWT en un decodificador online
Un JWT (JSON Web Token) son tres segmentos codificados en Base64URL unidos por puntos: un header, un payload y una firma. El header y el payload no están cifrados; simplemente están codificados. Cualquiera que tenga el token puede leer su contenido, incluido cualquier servicio que lo reciba, aunque solo sea para “decodificarlo del lado del cliente”.
Pueden suceder varias cosas entre que pulsas Cmd-V y ves los claims decodificados:
- Historial del navegador. Muchas herramientas históricamente pasaban el token en la query string de la URL, lo que significa que termina en el historial del navegador, en los referrers de pestañas padre y en cualquier backend de historial sincronizado (Chrome Sync, Firefox Sync, perfiles de Edge).
- Logs del servidor. Incluso las páginas que decodifican en JavaScript siguen haciendo peticiones para analíticas, fuentes y scripts publicitarios. Si el token está en la URL, aparece en las cabeceras
Refererenviadas a esos terceros. - SDKs de telemetría. Hasta septiembre de 2019, jwt.io enviaba métricas desde la página a pesar de anunciar operación únicamente del lado del cliente, como documentó el ingeniero Jamie Tanna (Capital One Open Banking). “Cliente” es una afirmación, no una auditoría.
- Cambios futuros de código. Un sitio que hoy es del lado del cliente puede desplegar mañana un cambio del lado del servidor. Como dijo un comentarista muy citado en Hacker News: “Si tienes la costumbre de usar estas herramientas, alguna acabará comprometiéndose. Ya sea por un hackeo técnico, presión financiera, compra por una entidad sin escrúpulos o un empleado descontento en algún punto del camino”.
Nada de esto requiere mala intención. Solo requiere que alguien, en algún lugar, entre tu teclado y tus ojos, tenga una copia de tu token el tiempo suficiente para usarla mal.
El modelo de amenazas real
La primera objeción siempre es la misma: “Pero el token expira en 15 minutos, ¿qué es lo peor que podría pasar?” Varias cosas, en realidad.
Replay dentro de la ventana de expiración. Quince minutos son tiempo de sobra para que un script que monitoriza un pipeline de analíticas, un archivo de log filtrado o una cabecera referrer agarre el token y llame a tu API como si fueras tú. Si el token es un refresh token (que puede ser válido durante días o semanas), la ventana es mucho mayor.
Los claims son un mapa del tesoro. Un payload típico incluye el ID de usuario (sub), el ID del tenant, la lista de roles, la audiencia (aud), el emisor (iss) y a menudo claims personalizados como email, flags internos o titularidades de funciones. Incluso un JWT expirado le dice a un atacante exactamente a qué usuario apuntar, qué API atacar y qué aspecto tiene la escalada de privilegios en tu empresa.
Los tokens no productivos filtran secretos con forma de producción. Los JWTs de sandbox de Open Banking y los tokens de integración con partners contienen a menudo huellas de certificados, IDs de claves y URLs de audiencia que se mapean directamente a la infraestructura de producción. Jamie Tanna describió que se “quemó varias veces” por compañeros que pegaban JWTs no productivos y certificados de sandbox de Open Banking en jwt.io.
Las consecuencias de cumplimiento son independientes del impacto. Si tu empresa está sujeta a SOC 2, ISO 27001, PCI-DSS o cualquier regla cercana a HIPAA, pegar una credencial en un servicio de terceros es reportable independientemente de si realmente se explotó algo. El hallazgo de auditoría es el incidente.
Los bugs en el manejo de JWT siguen apareciendo. CVE-2026-29000, un bypass de autenticación en el JwtAuthenticator de pac4j, se publicó a principios de este año. Los bugs de validación de tokens no son un problema de 2018; depurar JWTs es exactamente cuando los desarrolladores recurren a herramientas online, y exactamente cuando los tokens filtrados son más útiles para un atacante que está vigilando la misma rotación de bibliotecas.
Lo que han dicho los propios mantenedores de jwt.io
El argumento más fuerte contra pegar tokens en jwt.io viene del propio jwt.io.
En la issue #700 de GitHub, “The Future of JWT.io”, abierta el 19 de julio de 2024, un ingeniero de DevRel de Okta/Auth0 escribió, textualmente, que “pasar un token al sitio mediante parámetros de la URL ha generado preocupaciones sobre la privacidad del token”. La issue describe una reescritura planificada que cambia los parámetros de query a fragmentos de URL, divide decode/encode/verify en widgets separados y deja de cargar tokens automáticamente desde la URL al cargar la página.
Ese es el equipo que opera jwt.io comprometiéndose públicamente con un rediseño porque el manejo actual no es lo suficientemente privado. En el momento de escribir esto, partes del rediseño se han desplegado y otras no. El estado exacto te resulta irrelevante: el punto es que el listón de privacidad del propio operador es más alto que el del sitio heredado, y no tienes forma fiable de saber qué versión está usando un visitante cualquiera en un día cualquiera.
Por separado, The State of JWT Libraries on JWT.io de PentesterLab (28 de marzo de 2025) descubrió que la lista de bibliotecas curada de jwt.io sigue recomendando repositorios archivados en 2018, bibliotecas actualizadas por última vez en 2015 y al menos una implementación que soporta HMAC-MD5 (un algoritmo que no existe en la especificación de JWT). Una biblioteca de la lista extrae el valor alg mediante regex en lugar de parsear JSON; otra firma con “una cadena aleatoria de longitud aleatoria y el payload como secreto”. Louis Nyffenegger, fundador de PentesterLab, lo resume así: “Los desarrolladores pueden elegir, sin saberlo, bibliotecas inseguras o abandonadas”.
El catálogo de bibliotecas no es el mismo problema que la privacidad de los tokens, pero apunta en la misma dirección: la propiedad “popular y conveniente” está haciendo demasiado trabajo no justificado dentro de tu modelo de confianza.
Qué significa realmente “decodificador JWT del lado del cliente”
Un decodificador verdaderamente del lado del cliente hace tres cosas:
- Carga el código por HTTPS una vez y luego se ejecuta enteramente en la pestaña de tu navegador.
- Realiza la decodificación en JavaScript usando
atob()(o un helper de Base64URL) yJSON.parse()sobre los segmentos del header y del payload. - Verifica firmas opcionalmente mediante la Web Crypto API, la misma primitiva auditada que asegura tus handshakes TLS.
Sin fetch, sin XHR, sin navigator.sendBeacon, sin ping de analítica que arrastre el token. Los bytes del token nunca abandonan la memoria de la pestaña.
Eso no es lo que viene por defecto. Es una propiedad que una herramienta o tiene o no tiene, y que puedes verificar tú mismo en menos de un minuto.
Cómo verificar que una herramienta JWT es realmente del lado del cliente (receta de 60 segundos)
Esta es la habilidad más útil de todo este artículo. Aplícala a cada herramienta que toque credenciales, incluida la de remove.sh.
Método 1: la prueba del modo avión
- Abre la herramienta en una pestaña nueva.
- Espera a que la página cargue completamente.
- Desactiva el Wi-Fi o activa el modo avión.
- Pega un token y decodifícalo.
Si aparecen el header y el payload decodificados, la herramienta está haciendo el trabajo localmente. Si ves un spinner o un error, la herramienta está haciendo una llamada al servidor, probablemente con tu token en el cuerpo de la petición. Esta es la comprobación más rápida y definitiva.
Método 2: la auditoría de red en DevTools
- Abre DevTools (F12 o Cmd+Option+I).
- Cambia a la pestaña Network.
- Filtra por Fetch/XHR.
- Pulsa Clear (el icono de prohibido) y luego pega tu token.
Un decodificador del lado del cliente mostrará cero peticiones Fetch/XHR durante la decodificación. Si ves una petición, púlsala e inspecciona la pestaña Payload: tu token podría estar en el cuerpo de la petición o en la query string. Aunque no esté, la herramienta está accediendo a la red en cada pulsación de tecla, lo cual basta para descalificarla para trabajo sensible.
Método 3: lee la barra de URL
Si la herramienta mete el token directamente en la URL (?token=eyJhbG...), ese token está ahora en tu historial del navegador, en tu historial de shell si copiaste la URL, en la cabecera Referer enviada a cada script de analítica de la siguiente página que visites y en cualquier gestor de portapapeles que uses. Las herramientas que usan fragmentos de URL (#token=...) son mejores, porque los fragmentos no se envían a los servidores, pero los parámetros de query son una descalificación inmediata.
Pruébalo tú mismo: abre el JWT Decoder en remove.sh y luego ejecuta las tres comprobaciones. El panel Network permanece vacío después de cargar la página, la URL nunca contiene tu token y la página funciona dentro de un avión. Esa es una propiedad verificable, no una afirmación de marketing.
Una alternativa privada a jwt.io: decodifica en tu navegador
Si has llegado hasta aquí, la recomendación no sorprende: usa un decodificador que puedas verificar y luego verifícalo.
El JWT Decoder de remove.sh está construido sobre las mismas primitivas que describe este artículo. Usa atob() para los segmentos en Base64URL, JSON.parse() para el header y el payload, y la Web Crypto API para la verificación de firmas HMAC (HS256/HS384/HS512). Los tokens nunca se serializan a la URL. No hay un SDK de analítica leyendo el campo de entrada. La herramienta informa del estado de expiración comparando el claim exp con tu reloj local y etiqueta los claims registrados (iss, sub, aud, iat, nbf, jti) para que no tengas que memorizarlos.
Lo que no hace, hoy por hoy, es verificar firmas RSA o ECDSA (RS256/ES256). Para firmas asimétricas tienes dos opciones razonables, ambas cubiertas en la siguiente sección.
Si tu token viene envuelto como Authorization: Bearer eyJhbG..., pega la cosa entera: el decodificador elimina el prefijo Bearer automáticamente. Si solo tienes los segmentos codificados en Base64 y quieres inspeccionarlos en crudo, el Base64 Encoder & Decoder decodifica segmentos individuales sin intentar interpretarlos como un JWT, lo cual es útil cuando sospechas que un token está malformado.
Verificar firmas sin exponer tu secreto
Decodificar te dice qué afirma un token. Verificar te dice si confiar en él. No son la misma operación y tienen riesgos de privacidad distintos.
HMAC (HS256/HS384/HS512)
La verificación HMAC requiere el secreto compartido. Esta es la peligrosa: un secreto filtrado significa que cualquiera puede acuñar tokens válidos para tu servicio. Nunca pegues un secreto HMAC en una herramienta online de la que no puedas verificar que es local.
El JWT Decoder de remove.sh verifica firmas HMAC con la Web Crypto API. El secreto permanece en la memoria de tu pestaña y nunca se serializa a la red. Puedes confirmarlo ejecutando la prueba del modo avión con el token y el secreto rellenados; la verificación se completa igualmente.
Si quieres una garantía más fuerte que incluso una pestaña de navegador auditada, baja a la receta local de openssl que viene a continuación para recalcular el HMAC a partir de la porción header-payload y compararlo tú mismo con el segmento de la firma.
RSA / ECDSA (RS256, RS384, RS512, ES256, ES384, ES512)
La verificación asimétrica solo necesita una clave pública, que por definición no es secreta. Este es el caso fácil para herramientas online: los datos que circulan no son sensibles por sí mismos. Lo único que debes proteger es el token, que contiene los mismos claims independientemente del algoritmo.
Hasta que remove.sh despliegue verificación RSA/ECDSA en el decodificador, la opción local más limpia es step crypto:
step crypto jwt verify \
--jwks https://your-issuer.example.com/.well-known/jwks.json \
--iss https://your-issuer.example.com \
--aud your-audience < token.txt
O con openssl y una clave pública en formato PEM:
# Extract the signed portion (header.payload)
SIGNED=$(cut -d. -f1,2 token.txt)
# Extract the signature, decode Base64URL
cut -d. -f3 token.txt | tr '_-' '/+' | base64 -d > sig.bin
# Verify with openssl
echo -n "$SIGNED" | openssl dgst -sha256 -verify pubkey.pem -signature sig.bin
Ambas funcionan offline. Ambas te permiten verificar un token sin pegarlo nunca en una página web.
Decodificar un JWT localmente con la CLI
Para inspecciones puntuales fuera de cualquier navegador, dos one-liners cubren la mayoría de los casos.
Imprimir el header con formato:
cut -d. -f1 token.txt | tr '_-' '/+' | base64 -d 2>/dev/null | jq .
Imprimir el payload con formato:
cut -d. -f2 token.txt | tr '_-' '/+' | base64 -d 2>/dev/null | jq .
El paso tr '_-' '/+' convierte Base64URL a Base64 estándar, que es lo que esperan la mayoría de los decodificadores. El 2>/dev/null se traga la advertencia base64: invalid input que aparece cuando el segmento no tiene padding; jq seguirá imprimiendo el JSON correctamente.
Si no tienes jq, el JSON Formatter de remove.sh formatea con estilo la salida de cualquiera de los comandos en tu navegador sin enviarla a ningún sitio. Pásala al portapapeles con pbcopy (macOS) o xclip -sel clip (Linux) y pégala.
Cómo compartir un JWT con seguridad en un informe de bug
Una razón habitual por la que los desarrolladores recurren a jwt.io no es depurar, sino pegar un payload decodificado en un hilo de Slack o un ticket para que un compañero pueda ver los claims. Hay una receta más segura.
- Decodifica el token localmente con uno de los métodos anteriores.
- Copia solo el JSON decodificado, nunca la forma codificada
eyJhbG.... La forma codificada es la credencial; el JSON decodificado son simplemente datos. - Redacta los claims identificativos antes de compartir: sustituye
sub,email,name, IDs de usuario personalizados e IDs de tenant por valores marcadores (sub: "user-redacted"). - Elimina el segmento de la firma. No puede reconstruirse a partir del header y el payload sin el secreto o la clave privada, lo que significa que el JSON redactado deja de ser una credencial usable.
- Para fixtures de prueba, genera un token nuevo firmado con un secreto desechable. Lo que importa para reproducir un bug es la forma, no los valores.
Si un compañero necesita confirmar “sí, este es el mismo token que yo estoy viendo” sin que ninguno comparta el token en sí, pega el JWT codificado en el Hash Generator de remove.sh e intercambiad la huella SHA-256 en su lugar. Misma huella significa mismo token; la huella no revela nada sobre los claims ni la firma.
Este enfoque convierte un intercambio de credenciales en un intercambio de datos, que es lo que tu política de seguridad realmente quiere.
Preguntas frecuentes
¿Es jwt.io de código abierto?
El código del frontend del sitio está publicado en GitHub, pero “código abierto” no te dice qué se está ejecutando hoy en jwt.io. Como señaló Jamie Tanna, “no tenemos forma de saber si el código fuente… se está usando realmente” en el sitio en vivo. La verificabilidad (una pestaña Network que se mantiene vacía) es una señal más fuerte que un repo público.
¿Ha filtrado jwt.io tokens alguna vez?
No hay ninguna divulgación pública de un incidente de filtración de tokens. Hay un reconocimiento público de los mantenedores (GitHub #700) de que el manejo heredado vía query de URL generó preocupaciones de privacidad lo bastante serias como para motivar una reescritura. La ausencia de un incidente conocido no es lo mismo que la ausencia de riesgo.
¿Puedo autoalojar jwt.io?
Sí, el código está disponible, pero autoalojar solo resuelve el problema de la confianza en la red si realmente auditas el build y lo sirves desde una infraestructura que controlas. Para la mayoría de los equipos, una herramienta del lado del cliente ya verificada es menos trabajo y menos riesgo que mantener un fork.
¿Decodificar un JWT requiere el secreto?
No. Decodificar el header y el payload solo requiere decodificación Base64URL y parseo JSON: ambas operaciones puramente locales. El secreto solo se necesita para verificar la firma, que es un paso aparte. Cualquier herramienta que te pida el secreto solo para mostrarte los claims decodificados está haciendo algo mal.
¿Por qué mi token aparece como expirado aunque acabo de acuñarlo?
El claim exp se compara con el reloj local. Los decodificadores que se ejecutan en un navegador usan tu reloj del sistema; las herramientas CLI usan el reloj del host. Un reloj desfasado, habitual en VMs y runners de CI, hará que tokens válidos parezcan expirados y viceversa. Sincroniza tu reloj (sudo sntp -sS time.apple.com o sudo ntpdate pool.ntp.org) y vuelve a comprobarlo.
¿Es realmente seguro pegar un token en una herramienta que has verificado que es del lado del cliente?
Sí, con una salvedad. Una herramienta que hoy es del lado del cliente puede no serlo mañana. La comprobación de la pestaña Network hay que repetirla cuando confíes una herramienta con un token particularmente sensible, especialmente tras un parón largo. Marcar la herramienta como favorita o usar una extensión de navegador que avise sobre peticiones salientes desde un origen concreto abarata este coste.
¿Cómo se relaciona esto con la postura de privacidad más amplia de remove.sh?
La misma arquitectura se aplica a cada herramienta para desarrolladores del sitio. El argumento extendido está en Client-Side Developer Tools: The Privacy-First Approach, que cubre en detalle formateadores JSON, generadores de hashes, decodificadores Base64 y la Web Crypto API.
En resumen
jwt.io es una comodidad popular que maneja una clase de datos (credenciales) para la que “comodidad popular” no es un modelo de confianza suficiente. Sus propios mantenedores han escrito, públicamente, que el sitio heredado tiene problemas de privacidad lo bastante serios como para rediseñarlo. El reemplazo no es el rediseño de jwt.io ni un único competidor; es un hábito.
El hábito es: antes de que ninguna herramienta vea un token, ejecuta la prueba del modo avión. Si funciona offline, es local. Si no, encuentra una que lo haga, o recurre a un one-liner de CLI.
El JWT Decoder de remove.sh está construido para superar esa prueba. Ábrelo, desactiva tu red y decodifica un token. Si sigue funcionando (y lo hará), acabas de verificar, con tus propios ojos, que ningún tercero verá nunca ese JWT.
Esa es la respuesta a “alternativa privada a jwt.io”. No una marca diferente. Una propiedad verificable.