Skip to content
Back to Blog
developerjwt-decodersecurityauthentication

Cómo decodificar un JWT (Decodificar vs Verificar)

Cualquiera puede decodificar un JWT en base64 y leerlo; eso no es lo mismo que verificarlo. Aquí está la diferencia, los ataques que explotan la brecha y cómo decodificar de forma segura.

SZ
Founder, Molixa
10 min read
Compartir
Cómo decodificar un JWT (Decodificar vs Verificar)
Table of contents7 sections

Para decodificar un JWT, decodifica en base64url sus dos primeras partes separadas por puntos para leer el encabezado y el payload como JSON. Decodificar es solo leer: omite la firma, por lo que te dice lo que dicen los claims, no si son genuinos. Verificar es el paso aparte que demuestra que el token no fue alterado.

Esa distinción es clave. Un JWT está firmado, no cifrado, lo que significa que cualquiera que tenga el token puede leer todos los claims sin necesidad de una clave. Tratar "lo decodifiqué y los claims parecen correctos" como prueba de autenticidad es cómo las vulnerabilidades reales se cuelan en producción. Analicemos un token, veamos exactamente dónde termina la decodificación y comienza la verificación, y luego cubramos los ataques que viven en ese espacio.

Lo que realmente contiene un JWT#

Un JSON Web Token son tres secciones codificadas en base64url unidas por puntos:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0IiwibmFtZSI6IkFkYSIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTczNTY4OTYwMH0.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Las tres partes son header.payload.signature. Decodifica las dos primeras y obtienes JSON legible:

// Header
{ "alg": "HS256", "typ": "JWT" }

// Payload (los claims)
{ "sub": "1234", "name": "Ada", "role": "admin", "exp": 1735689600 }

El alg indica qué algoritmo firmó el token (aquí HMAC-SHA256). El payload contiene los claims: sub (sujeto/id de usuario), role y exp (fecha de expiración como timestamp Unix). La tercera parte, la firma, es un hash con clave de las dos primeras. Es crucial entender que el payload es solo base64url, que es codificación, no cifrado. Nunca pongas un secreto en el payload de un JWT. Cualquiera puede leerlo.

Base64url es una variante segura para URL de base64: reemplaza + y / por - y _ y elimina el relleno. Si alguna vez intentaste decodificar un JWT con una herramienta base64 estándar y obtuviste un error, el juego de caracteres suele ser la causa.

Decodificar vs Verificar: La Distinción Importante#

Estas dos operaciones parecen similares y a menudo se confunden en tutoriales. No son lo mismo, y mezclarlas es un error de seguridad.

DecodificarVerificar
Qué haceLee el encabezado y el payloadConfirma que la firma es válida
¿Necesita una clave?NoSí (clave secreta o pública)
¿Puede hacerlo un extraño?Sí, con cualquier herramienta base64No, solo la contraparte del firmante
¿Prueba autenticidad?No
Cuándo usarloDepuración, inspección de claimsCada vez que confíes en el token

Aquí está la diferencia en código. Decodificar es trivial y no requiere confianza:

// SOLO DECODIFICAR: lee claims, no prueba nada
function decodeJwt(token) {
  const [header, payload] = token.split(".");
  const json = (part) =>
    JSON.parse(atob(part.replace(/-/g, "+").replace(/_/g, "/")));
  return { header: json(header), payload: json(payload) };
}

const { payload } = decodeJwt(token);
console.log(payload.role); // "admin" ... pero ¿es real este token?

Ese código devuelve felizmente role: "admin" para cualquier token que le des, incluido uno falsificado hace cinco segundos. Verificar es lo que hace que los claims sean confiables:

// VERIFICAR: comprueba la firma y la expiración antes de confiar
import jwt from "jsonwebtoken";

try {
  const claims = jwt.verify(token, process.env.JWT_SECRET, {
    algorithms: ["HS256"], // fija el algoritmo explícitamente
  });
  // Solo ahora es seguro actuar sobre claims.role
  grantAccess(claims.role);
} catch (err) {
  // Firma inválida, token expirado o algoritmo no permitido
  denyAccess();
}

La regla es simple: decodificar para mirar, verificar para confiar. Cualquier ruta de código que tome una decisión de autorización debe verificar. Decodificar sin verificar en el servidor equivale a permitir que los usuarios editen sus propios permisos.

Los ataques que viven en la brecha#

Cuando los desarrolladores omiten o manejan mal la verificación, se abren tres ataques clásicos. Todos explotan el hecho de que el token está controlado por el atacante hasta que la firma se verifica correctamente.

El ataque del algoritmo "none"#

La especificación JWT incluye un valor alg de none, que significa "sin firma". Si un servidor lee el algoritmo del encabezado del propio token y confía en él, un atacante puede eliminar la firma, establecer "alg": "none" y falsificar cualquier carga útil que desee:

// Encabezado falsificado por el atacante
{ "alg": "none", "typ": "JWT" }

// Carga útil falsificada por el atacante: administrador instantáneo
{ "sub": "9999", "role": "admin" }

Con la firma eliminada y alg establecido en none, un verificador ingenuo que "respeta" el encabezado lo acepta. La solución es nunca permitir que el token dicte su propio algoritmo. Fije el algoritmo esperado en el lado del servidor, exactamente como la opción algorithms: ["HS256"] anterior, para que none y cualquier otro valor inesperado sean rechazados de plano.

El ataque de confusión de algoritmos (RS256 a HS256)#

Este es más sutil y ha afectado a bibliotecas importantes. Suponga que su sistema firma tokens con RS256 (asimétrico: una clave privada firma, una clave pública verifica). La clave pública es, por definición, pública.

Un atacante toma esa clave pública, cambia el encabezado a "alg": "HS256" (HMAC simétrico) y firma un token falsificado usando la clave pública como secreto HMAC. Un verificador vulnerable que toma el algoritmo del encabezado ejecutará la verificación HMAC usando la clave pública que ya tiene, y la firma falsificada será válida. El atacante acaba de usar su clave de verificación publicada para firmar tokens.

La defensa es el mismo principio: fije el algoritmo. Si su servidor espera RS256, configúrelo para aceptar solo RS256 y verifique con la clave pública como una clave RSA, nunca como un secreto HMAC. Permitir que el encabezado elija es la causa raíz cada vez.

Ignorar la caducidad y otras reclamaciones#

Incluso una firma perfectamente verificada no significa que el token sea válido actualmente. La verificación confirma que el token fue emitido por usted y no ha sido alterado; no verifica por sí sola que el token aún esté vigente o destinado a esta audiencia. Siempre valide:

  • exp (caducidad) y nbf (no antes) para rechazar tokens caducados o con fecha futura.
  • aud (audiencia) para que un token emitido para un servicio no pueda ser reutilizado contra otro.
  • iss (emisor) para aceptar solo tokens del proveedor de identidad en el que confía.

La mayoría de las bibliotecas verifican exp automáticamente al llamar a verify, pero aud e iss generalmente requieren que pase los valores esperados explícitamente.

Dónde almacenar y enviar el token también importa#

La verificación protege el contenido del token, pero el manejo del token es su propia superficie de ataque. Algunos puntos no negociables:

  • Prefiere cookies HTTP-only en lugar de localStorage para los tokens de sesión, así los scripts del lado del cliente (y cualquier payload XSS) no pueden leerlos.
  • Usa siempre HTTPS para que el token no sea interceptado durante la transmisión.
  • Mantén los payloads mínimos y no sensibles. Como cualquiera puede decodificar el payload, nunca almacenes contraseñas, PII completa o secretos allí.
  • Usa tiempos de vida cortos más tokens de actualización para que un token de acceso filtrado expire rápidamente.

Un token filtrado es un token válido hasta que expire. Por eso los plazos de caducidad y la higiene del almacenamiento importan tanto como las matemáticas de la firma.

Cómo decodificar un JWT de forma segura para depuración#

Constantemente necesitarás inspeccionar tokens al construir autenticación: verificar qué claims emitió un proveedor de identidad, depurar un error 401 o confirmar una fecha de expiración. El problema es que un JWT es una credencial activa. Pegar un token de sesión real en un sitio web aleatorio significa que el servidor de ese sitio ahora tiene un token funcional para tu cuenta.

Paso 1: Usa un decodificador que funcione en tu navegador#

Busca un decodificador JWT gratuito que realice todo el análisis del lado del cliente. Cuando la decodificación ocurre completamente en la pestaña del navegador, el token nunca se transmite a ningún lado, por lo que incluso un token de producción permanece en tu máquina. Este es el hábito más importante al manejar tokens reales: confirma que la herramienta sea del lado del cliente antes de pegar.

Paso 2: Lee el encabezado, el payload y la expiración#

El decodificador divide el token y muestra el encabezado y el payload como JSON formateado, además de una expiración legible para que no tengas que convertir una marca de tiempo Unix manualmente. Verifica el alg, revisa los claims y confirma que exp esté en el futuro. Recuerda que en esta etapa solo estás leyendo, no validando.

Paso 3: Verifica la firma solo con un secreto que no sea de producción#

Si el decodificador y verificador JWT te permite probar una firma, solo pega un secreto de prueba o desarrollo, nunca una clave de firma de producción, en ningún formulario web. La matemática de firmas también se puede reproducir localmente: una firma HS256 es solo un HMAC, que puedes calcular con un generador de hash, y las partes en base64url se decodifican con un codificador y decodificador Base64. Para una visión más amplia sobre el manejo seguro de tokens, consulta nuestra guía sobre decodificadores JWT y seguridad de tokens.

La Conclusión Final#

Decodificar un JWT lee los reclamos; verificar demuestra que son auténticos. Son operaciones diferentes con requisitos distintos, y confundirlas es la raíz del ataque del algoritmo none y los ataques de confusión de algoritmo. En el servidor, verifica cada token, fija el algoritmo explícitamente y revisa exp, aud e iss. Para depuración, decodifica localmente para que una credencial activa nunca salga de tu navegador.

Preguntas Frecuentes#

¿Cómo decodifico un JWT? Divide el token por sus dos puntos en tres partes, luego decodifica en base64url la primera parte (encabezado) y la segunda parte (carga útil) a JSON. La tercera parte es la firma y no está destinada a ser leída. Decodificar no requiere clave y solo te muestra las reclamaciones, no confirma que el token sea auténtico.

¿Cuál es la diferencia entre decodificar y verificar un JWT? Decodificar lee el encabezado y la carga útil y no necesita clave, por lo que cualquiera puede hacerlo. Verificar recalcula la firma con la clave secreta o pública para confirmar que el token fue emitido por ti y no ha sido alterado. Decodificar te dice lo que dicen las reclamaciones; solo verificar te dice si debes confiar en ellas.

¿Es seguro decodificar un JWT en línea? Solo con una herramienta que decodifique completamente en tu navegador. Un JWT es una credencial activa, por lo que pegar un token de sesión real en un sitio que lo envía a un servidor entrega a ese servidor un token funcional para tu cuenta. Usa un decodificador del lado del cliente para que el token nunca salga de tu pestaña.

¿Qué es el ataque del algoritmo "none" en JWT? Explota servidores que leen el algoritmo de firma del propio encabezado del token. Un atacante establece "alg": "none", elimina la firma y falsifica cualquier carga útil. Un verificador que respeta el encabezado acepta el token sin firmar. La solución es fijar el algoritmo esperado en el servidor y rechazar none directamente.

¿Alguien puede leer los datos dentro de mi JWT? Sí. Un JWT está firmado, no cifrado, por lo que la carga útil solo está codificada en base64url y cualquiera que tenga el token puede decodificar y leer cada reclamación. Nunca almacenes contraseñas, secretos o datos personales sensibles en la carga útil de un JWT. La firma protege contra la manipulación, no contra la lectura.

¿Cómo verifico si un JWT ha expirado? Decodifica la carga útil y lee la reclamación exp, una marca de tiempo Unix en segundos; si está en el pasado, el token ha expirado. Durante la verificación real, la mayoría de las bibliotecas rechazan automáticamente los tokens expirados cuando llamas a verify. Un decodificador que muestra una fecha de caducidad legible te permite confirmar esto rápidamente mientras depuras.

developerjwt-decodersecurityauthentication

More from Molixa

Try Molixa Tools

50+ free AI tools for content creation, SEO, coding, and more. No signup, no watermark.

Explore all tools