JWT encode/decode: crear e inspeccionar un token en línea

JWT encode/decode: crear e inspeccionar un token en línea

Decodifica la cabecera y el payload de un JWT o firma un token de prueba en tu navegador: HS256, RS256, ES256, sin enviar el secreto a un servidor ajeno.

04.10.2026
17 min de lectura
Compartir este artículo:
JWT
Autenticación
Tokens
Seguridad
Tutorial

Un JWT lo puede leer cualquiera: decodifica para inspeccionar, firma para probar, verifica para confiar

Un JSON Web Token parece opaco, pero sus dos primeros segmentos son JSON corriente codificado en Base64URL: quien tenga el token puede leerlo. Es justo lo que necesitas cuando una API responde 401 y quieres saber qué afirma el token. El decodificador JWT en línea de FastMinify decodifica la cabecera y el payload en cuanto pegas el token, y el codificador JWT firma un token a partir de una cabecera y un payload JSON editables, en directo y sin botón de envío. Ambos funcionan en tu navegador: el token, los claims y el secreto no se envían a ninguna parte. Decodificar, sin embargo, no es verificar. Cualquiera puede escribir "role": "admin" en un payload, así que lo que dice un token decodificado no prueba nada sobre quién lo emitió. Comprobar una firma con las claves públicas de un emisor, la audiencia, el emisor y la expiración es tarea de jwt-verify, que acepta un JWKS pegado, y inspect-jwks muestra qué contiene un conjunto de claves así. Esta guía explica cómo se construye un JWT, cómo depurar un 401 o un 403 con un token decodificado, los errores que convierten una herramienta de pruebas en un agujero de seguridad y las mismas operaciones en Node con la biblioteca jose. Las herramientas están en el hub de herramientas de seguridad.

Decodificar: pega el token compacto y la cabecera y el payload aparecen como JSON formateado. Un JWT tiene exactamente tres partes separadas por puntos; la firma solo puede estar vacía si la cabecera indica alg=none
Codificar: firma en directo, sin botón de envío. Algoritmos: none, HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512 y EdDSA (solo Ed25519)
Al codificar, iat se reescribe siempre a la hora actual. El menú Expiración (Ninguna, 15 minutos, 1 hora, 24 horas) sobrescribe exp respecto a iat; «Ninguna» deja tu payload como está
Los tokens HMAC piden un secreto (leído opcionalmente como bytes Base64URL); RSA, ECDSA y EdDSA piden una clave privada PEM (PKCS#8) o JWK
Comprobación de firma opcional junto al decodificador, con un secreto o una clave pública: revisa solo la firma, nunca exp, aud ni iss
Todo queda en la pestaña: ningún token, claim ni clave se envía a un servidor

Codificar, decodificar o verificar: qué herramienta responde a cada pregunta

Usos adecuados

El decodificador y el codificador cubren todo lo que no exige establecer confianza en un emisor.

Leer los claims de un token copiado de la pestaña Red (exp, aud, scope) antes de culpar a una ruta de la API
Construir un token de fixture para un test de integración: HS256, un secreto desechable, una expiración de 15 minutos o 1 hora
Producir un token con una cabecera concreta (alg, kid) para ver cómo lo rechaza tu API
Comprobar que un token HS256 se firmó con el secreto que crees: pega el secreto junto al decodificador
Enseñar o aprender el formato compacto: cambia un carácter del payload y observa cómo cambia el segmento de firma
Lo que corresponde a otra herramienta

Confiar en un token requiere claves, claims y una política, no solo un payload legible. Pasa a jwt-verify, a inspect-jwks o a tu propio código.

Verificar un token con las claves públicas de un proveedor de identidad: pega el JWKS en <a href="/es/jwt-verify" class="text-primary hover:underline">jwt-verify</a>, que comprueba la firma, la expiración, la audiencia y el emisor, con una tolerancia de reloj de 0, 60 o 300 segundos. Nunca descarga un JWKS de la red
Ver qué claves contiene un JWKS (kid, kty, alg) antes de depurar un «key not found»: <a href="/es/inspect-jwks" class="text-primary hover:underline">inspect-jwks</a>
Emitir y validar tokens en producción: una biblioteca mantenida en el servidor, con el algoritmo fijado. Nunca una página web
Revocar una sesión: un JWT firmado sigue siendo válido hasta exp por sí mismo; es una cuestión de diseño de tu flujo de autenticación, fuera de lo que puede decir un decodificador
Guardar contraseñas de usuarios: un hash lento y con sal, no un JWT. Consulta la <a href="/es/blog/generar-contrasena-segura-en-linea" class="text-primary hover:underline">guía del generador de contraseñas</a> y la <a href="/es/bcrypt-hash" class="text-primary hover:underline">herramienta bcrypt</a>

Depurar un 401 o un 403 con un token decodificado

401: caducado, aún no válido o dañado

Pega el token en el decodificador y lee los claims de tiempo antes de tocar la API. exp, nbf e iat son valores NumericDate: segundos desde el 1 de enero de 1970 UTC (RFC 7519).

Un exp de 13 cifras son milisegundos, no segundos: el productor se equivoca, y muchas bibliotecas lo leerán como una fecha a decenas de miles de años
Convierte el valor en una consola: <code>new Date(exp * 1000).toISOString()</code>. El decodificador muestra el número bruto y no lo convierte por ti
Resta iat de exp: el resultado es la vida del token en segundos (3600 para una hora). Una duración de 0 o negativa apunta a una mala configuración del emisor
Un nbf en el futuro, o un iat adelantado respecto al reloj de la API, indica desfase de reloj entre emisor y API: los servidores suelen aceptar una pequeña tolerancia, y jwt-verify permite probar 0, 60 y 300 segundos
Pega solo el token compacto. Un prefijo <code>Bearer </code>, un salto de línea o un carácter cortado por un log hace que el decodificador informe de un token inválido o de un número de partes incorrecto
401 con un token que parece correcto: algoritmo, clave y firma

Cuando los claims son correctos y la API rechaza igualmente, el problema está en la cabecera o en la firma.

alg en la cabecera debe ser el que espera la API. Una API fijada en RS256 rechaza un token HS256, y al revés
kid nombra una clave del conjunto de claves del emisor: abre el JWKS en <a href="/es/inspect-jwks" class="text-primary hover:underline">inspect-jwks</a> y comprueba que existe y que su alg y su kty coinciden
Pega el secreto HMAC junto al decodificador: «Firma no válida» con un secreto que parece correcto suele significar que la opción Base64URL es incorrecta (ver más abajo) o que el token se alteró por el camino
Un token con cinco partes separadas por puntos es un JWE cifrado, no un JWT firmado. El decodificador lo rechaza, porque espera exactamente tres partes
Un token copiado de una cookie o de una cabecera puede estar truncado por un límite de tamaño: un último segmento ausente es el síntoma típico
403: autenticado, pero sin permiso

Un 403 significa que el token se aceptó y la autorización dijo que no. El payload suele explicar por qué.

aud debe contener el identificador que la API espera, e iss debe coincidir con el emisor en el que confía. Un token emitido para otra API u otro tenant falla aquí
Los permisos viven bajo nombres de claim distintos según el proveedor: scope, scp, roles o permissions. Comprueba el que tu API lee realmente
Una cadena scope va separada por espacios (<code>"orders:read orders:write"</code>), mientras que los roles suelen ser un array: un código que trata uno como el otro lo deniega todo en silencio
sub identifica al usuario, no a la aplicación: un token de servicio a servicio puede llevar ahí un identificador de cliente
Un permiso recién cambiado no está en un token emitido antes del cambio: decodifica un token nuevo antes de concluir que la regla está mal

Cuatro errores que convierten una herramienta de pruebas en un agujero de seguridad

Tratar un token decodificado como un token de confianza

Un decodificador muestra lo que un token afirma, no quién lo escribió. El payload no está protegido: quien tiene el token, o puede fabricar uno, puede meter cualquier claim. El codificador puede incluso producir un token no seguro con alg=none, cuyo segmento de firma está vacío: las herramientas lo etiquetan como «JWT sin firmar (alg=none)», y ningún verificador debería aceptarlo jamás. La RFC 8725 (buenas prácticas para JWT) pide a los servidores aceptar solo los algoritmos esperados y no dejar nunca que el token elija. La confusión de algoritmo es el fallo clásico: un token que declara HS256 y está firmado con la clave pública de un servicio RS256 pasa un verificador que lee alg de la cabecera y usa la clave pública como secreto HMAC.

Leer <code>"role": "admin"</code> en un payload decodificado como prueba de que el usuario es administrador
Aceptar el alg que declare la cabecera del token, incluido none
Decidir autorizaciones en un front a partir de claims nunca verificados
Tomar el «Firma verificada» de un decodificador como sustituto de las comprobaciones de audiencia, emisor y expiración
Creer que el payload es secreto

Base64URL es una codificación, no un cifrado: la guía de Base64 explica la diferencia. Un JWT firmado (JWS) solo garantiza la integridad, así que todo el payload es legible. Existen tokens cifrados (JWE, RFC 7516, cinco partes en lugar de tres), pero el decodificador de aquí solo trata tokens firmados. Un token es además una credencial: quien lo tiene puede usarlo hasta exp. Esta herramienta lo mantiene en tu pestaña, pero compartir pantalla, una captura compartida o un ticket con el token pegado lo filtran igualmente.

Poner una contraseña, un número de tarjeta o una dirección personal en un claim
Pegar un token de producción todavía válido en un ticket, un chat o una web de terceros
Registrar en logs la cabecera Authorization completa
Suponer que un token de aspecto ilegible es un token protegido
Secretos HMAC débiles o mal leídos

HS256 firma con un secreto compartido, y la RFC 7518 pide una clave al menos tan larga como la salida del hash: 256 bits para HS256, 384 para HS384, 512 para HS512. Cuando tu secreto es más corto, el codificador muestra su tamaño en bits frente al mínimo recomendado. Esa cifra es la longitud de la clave, no su aleatoriedad: una frase de 32 caracteres en español mide 256 bits de largo y sigue siendo adivinable. Quien posee un solo token puede probar secretos candidatos sin conexión contra su firma, sin tocar nunca tu API. Genera el secreto al azar, por ejemplo con el generador de contraseñas (consulta la guía de contraseñas): unos 41 caracteres de su juego por defecto de 82 caracteres aportan 256 bits de entropía. La opción Base64URL cambia los bytes usados: marcada, la cadena del secreto se decodifica como Base64URL y sus bytes son la clave; sin marcar, los propios caracteres son la clave. El mismo texto con el ajuste equivocado da otra firma.

Usar <code>secret</code>, <code>changeme</code> o el nombre del proyecto como clave HS256
Leer «256 bits de largo» como «256 bits de entropía»
Firmar con la opción Base64URL activada y verificar con ella desactivada, o al revés
Compartir un mismo secreto HMAC entre servicios que no deberían poder emitir todos tokens
Dejar que un token de prueba salga de la prueba

El codificador está pensado para fixtures y depuración. Reescribe iat a ahora, puede suprimir la firma por completo y los ejemplos que carga usan secretos desechables. Un token firmado aquí con un secreto de demostración nunca debe ser aceptado por un entorno real, y un secreto de firma real nunca debe pegarse en un archivo que luego subas al repositorio. Si ya ocurrió, cámbialo y analiza tu diff antes de hacer commit con el escáner de secretos.

Subir al repositorio un token de prueba de larga duración cuyo secreto también funciona en staging
Mantener un atajo alg=none «para desarrollo local» tras una bandera que llega a producción
Reutilizar el mismo secreto de firma en desarrollo, staging y producción
Olvidar que un exp de 24 horas en una fixture sigue siendo una credencial durante 24 horas

Anatomía de un JWT: tres segmentos Base64URL y lo que dice cada uno

header.payload.signature

La forma compacta son tres segmentos Base64URL unidos por puntos. Es lo que viaja en una cabecera Authorization: Bearer.

Cabecera: un objeto JSON como <code>{"alg":"HS256","typ":"JWT"}</code>, que se codifica como <code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</code>. Nombra el algoritmo de firma y, con claves asimétricas, normalmente un kid.
Payload: un objeto JSON de claims, por ejemplo de quién habla el token, quién lo emitió, quién puede usarlo y hasta cuándo.
Firma: calculada sobre <code>base64url(header) + "." + base64url(payload)</code> con el algoritmo de la cabecera. Con HS256 es un HMAC-SHA-256 con el secreto compartido.
Base64URL (RFC 7515) usa <code>-</code> y <code>_</code> en lugar de <code>+</code> y <code>/</code> y elimina el relleno <code>=</code>, de modo que un JWT puede ir en una URL o en una cabecera sin cambios.
Cambia un carácter de la cabecera o del payload y la firma deja de coincidir: es la única protección que ofrece el formato.
Los claims que se leen primero

Siete claims registrados (RFC 7519) cubren la mayoría de las sesiones de depuración. Todos son opcionales en la especificación, así que una API puede exigir más que el estándar.

iss: el emisor, normalmente una URL. sub: el sujeto, normalmente un ID de usuario. aud: la audiencia, una cadena o un array.
exp: la expiración, nbf: no antes de, iat: emitido en. Los tres son NumericDate: segundos desde el 1 de enero de 1970 UTC.
jti: un identificador único del token, útil cuando un servidor mantiene una lista de denegación.
Ejemplo: iat 1790000000 es 2026-09-21T14:13:20Z, y exp 1790003600 una hora después, 15:13:20Z.
Los claims personalizados como scope, roles o tenant dependen del proveedor. La especificación no los define.
Familias de algoritmos: qué firma y qué verifica

El valor de alg decide quién puede emitir un token y quién solo puede comprobarlo.

HS256, HS384, HS512: un único secreto compartido firma y verifica, así que cualquier verificador también puede falsificar tokens.
RS256/384/512 y PS256/384/512 (RSA), ES256/384/512 (ECDSA), EdDSA (Ed25519): una clave privada firma, una clave pública verifica. Las claves públicas son lo que un proveedor de identidad publica como JWKS.
El codificador admite todos ellos y además none, que produce un token terminado en un punto, sin firma alguna.
EdDSA significa aquí solo Ed25519, que es el alcance documentado de la herramienta.
Elige un algoritmo asimétrico cuando varios servicios deban verificar tokens que solo un servicio puede emitir.

Decodificar y codificar en las herramientas: el recorrido

Inspeccionar un token con jwt-decode

El decodificador JWT no tiene botón: la decodificación se ejecuta mientras pegas o editas, tras una breve pausa. El editor empieza vacío; «Cargar ejemplo» o elegir un algoritmo carga un token de demostración.

1

Pega el token compacto

Solo los tres segmentos, sin el prefijo Bearer . Los espacios al principio y al final se ignoran.

2

Lee la cabecera y el payload

Ambos aparecen como JSON formateado en su propio panel, junto a la firma en bruto. Comprueba primero alg, kid, exp, aud e iss.

3

Comprueba la firma si hace falta

Pega el secreto HMAC o, para los algoritmos asimétricos, una clave pública en PEM o JWK. El resultado es «Firma verificada» o «Firma no válida», y cubre solo la firma.

4

Lee el error, si lo hay

El decodificador informa de un número de partes incorrecto, un segmento vacío, una firma ausente (permitida solo con alg=none) o un segmento que no es JSON en Base64URL.

Crear un token de prueba con jwt-encode

El codificador JWT firma mientras escribes. El token aparece en cuanto la cabecera, el payload y la clave son válidos.

1

Elige el algoritmo

Usa la barra de herramientas o edita alg en el JSON de la cabecera. Un alg ausente o no compatible se señala como cabecera no válida.

2

Escribe los claims

Un objeto JSON. iat se sobrescribe con la hora actual en cada codificación, así que no puedes fijar un iat antiguo.

3

Fija una expiración si la necesitas

El menú Expiración (15 minutos, 1 hora, 24 horas) sobrescribe cualquier exp del JSON. «Ninguna» deja tu payload como está.

4

Proporciona la clave

Un secreto para HMAC, o una clave privada PEM (PKCS#8) o JWK para RSA, ECDSA y EdDSA. Un secreto por debajo de la longitud recomendada muestra un aviso con su tamaño en bits.

5

Copia el token y compruébalo

Pégalo en el decodificador para ver lo que has producido y luego en jwt-verify para probar una política de verificación real.

Lo que las herramientas no hacen

Algunos límites que conviene conocer antes de apoyarse en ellas para un uso concreto.

Sin validación de exp, nbf, aud ni iss en el decodificador ni en el codificador: eso lo hace jwt-verify
Sin conversión de marcas de tiempo a fechas: el decodificador muestra los segundos en bruto
Sin descarga remota de JWKS en ningún sitio: las claves se pegan
Sin tokens cifrados (JWE): solo firmados, de tres partes
EdDSA se limita a Ed25519
Un token firmado aquí es una fixture, no autenticación de producción

Las mismas operaciones en tu propio código

Node: decodificar sin verificar

Decodificar no requiere biblioteca: divide por los puntos y lee cada segmento como Base64URL. Es lo que hace el decodificador, con el mismo límite: no se comprueba nada.

Ejemplo básico

// Decode WITHOUT verifying: read the claims, trust nothing. function decodeJwt(token) { const [h, p, s] = token.split('.') if (!h || !p || !s) throw new Error('Se esperaba header.payload.signature') const json = (part) => JSON.parse(Buffer.from(part, 'base64url').toString('utf8')) return { header: json(h), payload: json(p) } } const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzQyIiwic2NvcGUiOiJvcmRlcnM6cmVhZCIsImlzcyI6Imh0dHBzOi8vYXV0aC5leGFtcGxlLmNvbSIsImF1ZCI6Im9yZGVycy1hcGkiLCJpYXQiOjE3OTAwMDAwMDAsImV4cCI6MTc5MDAwMzYwMH0.S7icJbfp1NQ88Pkyf9HYZ6tl-jkLgOCOzxFDSCKFLvE' const { header, payload } = decodeJwt(token) console.log(header.alg) // HS256 console.log(new Date(payload.exp * 1000).toISOString()) // 2026-09-21T15:13:20.000Z // Pega este token en jwt-decode; con el secreto "demo-secret-for-docs-only-0123456789abcdef" muestra «Firma verificada»
Firmar con jose

La biblioteca jose firma un JWT compacto y rellena los claims registrados por ti. A diferencia del codificador de aquí, setIssuedAt() usa el reloj real, como corresponde en producción.

Ejemplo básico

import { SignJWT } from 'jose' // HS256: key of at least 32 bytes (256 bits), read from the environment const secret = new TextEncoder().encode(process.env.JWT_SECRET) const token = await new SignJWT({ scope: 'orders:read' }) .setProtectedHeader({ alg: 'HS256', typ: 'JWT' }) .setSubject('user_42') .setIssuer('https://auth.example.com') .setAudience('orders-api') .setIssuedAt() .setExpirationTime('1h') .sign(secret)
Verificar con el algoritmo fijado

La verificación es donde se establece la confianza: fija el algoritmo, el emisor y la audiencia, y permite una pequeña tolerancia de reloj.

Ejemplo básico

import { jwtVerify } from 'jose' try { const { payload } = await jwtVerify(token, secret, { algorithms: ['HS256'], // fija el algoritmo aceptado: nunca lo leas de la cabecera del token issuer: 'https://auth.example.com', audience: 'orders-api', clockTolerance: 60, // segundos de tolerancia por desfase de reloj entre el emisor y la API }) console.log(payload.sub) } catch (err) { // ERR_JWT_EXPIRED, ERR_JWS_SIGNATURE_VERIFICATION_FAILED, ERR_JWT_CLAIM_VALIDATION_FAILED… console.error(err.code) }
FastMinify jwt-decode y jwt-encode

Nada que instalar y nada enviado: el decodificador y el codificador cubren la lectura de claims, la creación de fixtures y la comprobación de una firma de la que tienes la clave. Las contrapartidas: sin validación de claims, sin conversión de marcas de tiempo, sin JWE, EdDSA limitado a Ed25519. Para una decisión de confianza real, usa una biblioteca de verificación en el servidor, o pega un JWKS en jwt-verify para probar antes tu política.

Conclusión

Un JWT es un sobre firmado, no sellado: su payload lo puede leer cualquiera, y solo la firma indica que no se ha modificado. El decodificador JWT hace visibles los claims en segundos, que es casi todo lo que necesita un 401 o un 403, y el codificador JWT crea un token para reproducir un caso. Ninguno de los dos establece confianza. Eso requiere las claves del emisor, un algoritmo fijado y comprobaciones de aud, iss y exp, que es lo que hacen jwt-verify y tu propio código de servidor. Mantén los secretos de prueba fuera de producción, genera los secretos HMAC al azar y rechaza alg=none. El hub de herramientas de seguridad reúne las herramientas vecinas para claves, certificados y secretos.

Inspecciona o crea un token en tu navegador

Decodifica para depurar, verifica para confiar: un payload legible no prueba nada
Lee exp, nbf e iat como segundos desde 1970 y conviértelos tú mismo
Fija el algoritmo en el servidor y rechaza alg=none
Genera los secretos HMAC al azar, al menos tan largos como la salida del hash
Nunca pegues un token de producción activo donde otros puedan verlo, y trata cada token como una credencial
Compartir este artículo
Compartir este artículo: