Saltar al contenido
Aback Tools Logo

Cómo Validar la Configuración JWT en TypeScript: Algoritmos, Claims y Secretos

Cómo validar la configuración JWT en TypeScript: forzar algoritmos en jwt.verify(), validar claims exp/nbf/iss/aud, rotar claves con JWKS y depurar tokens con herramientas basadas en navegador.

DH
Tutorials & How-Tos12 min de lectura2,750 palabras

La mayoría de los errores de JWT en TypeScript no están en el token: están en la configuración de verificación. Una restricción de algoritmo ausente, un claim de emisor sin comprobar o un secreto de vida corta pueden minar silenciosamente la autenticación de una forma que solo se manifiesta en producción. Esta guía recorre cada dimensión de la corrección de configuración JWT en TypeScript: algoritmos, validación de claims, higiene de secretos, gestión de expiración y las herramientas de navegador que aceleran la depuración.

3Partes del encabezado JWTencabezado · payload · firma
RS256Algoritmo recomendadoAsimétrico, seguro en producción
0 KBSubidas al servidorDepuración JWT en el navegador

Qué cubre la validación de configuración JWT

Un JSON Web Token (JWT) es una cadena compacta y segura para URL compuesta por tres partes codificadas en Base64URL separadas por puntos: un encabezado que declara el algoritmo y el tipo de token, un payload que transporta los claims y una firma que los une. Validar un JWT significa confirmar que las tres partes están intactas y que los claims cumplen los requisitos de tu aplicación, no solo que la firma es matemáticamente correcta.

Las dos capas de la validación JWT

La validación criptográfica confirma la firma: el servidor verifica que el token fue firmado con la clave esperada y que no ha sido manipulado. La validación de configuración va más allá: comprueba que el token fue emitido por la autoridad correcta, está destinado a este servicio concreto, no ha expirado y transporta los claims personalizados esperados. La mayoría de las vulnerabilidades de seguridad JWT provienen de una validación de configuración incompleta, no de una criptografía rota.

  • Algoritmo (`alg`) - debe coincidir exactamente con la configuración de tu servidor; nunca lo infieras del encabezado del token
  • Expiración (`exp`) - el token no debe haber pasado su marca de tiempo de expiración, con tolerancia de reloj
  • No-antes-de (`nbf`) - el token no debe usarse antes de su primera hora válida
  • Emisor (`iss`) - el token debe provenir de tu servicio de autenticación de confianza
  • Audiencia (`aud`) - el token debe estar destinado a esta API o servicio concreto
  • Claims personalizados - rol, scope, ID de tenant o cualquier campo específico de la aplicación del que dependa tu lógica

Note

La validación de la estructura JWT (comprobar que el token es una cadena Base64URL válida de tres partes) es un prerrequisito de todas las demás validaciones. El [Decodificador y Validador JWT](/tools/data/validators/jwt-decoder-and-validator) lo hace al instante en tu navegador: útil para confirmar que un token está bien formado antes de escribir el código de verificación.

Comprobaciones de algoritmo y configuración de claves

La configuración del algoritmo es el ajuste más crítico para la seguridad en la verificación JWT. Equivocarse habilita una clase de ataques que omiten la autenticación por completo. Las librerías JWT de TypeScript te dan las herramientas para aplicarlo correctamente, pero solo si las usas de forma explícita.

HS256 vs RS256 - elegir el algoritmo correcto

PropiedadHS256 (simétrico)RS256 (asimétrico)
Tipo de claveSecreto compartido (misma clave para firmar y verificar)Par de claves RSA (privada para firmar, pública para verificar)
Distribución de clavesCada verificador posee el secretoSolo el emisor posee la clave privada
Seguridad multi-servicio✗ Arriesgado - todos los verificadores pueden falsificar tokens✓ Los verificadores solo tienen la clave pública
Soporte OIDC / JWKS✗ No aplicable✓ Claves públicas servidas vía endpoint JWKS
Rendimiento✓ Rápido (HMAC)✗ Más lento (matemática RSA)
Mejor paraHerramientas internas, APIs de un solo servicioAPIs de producción, sistemas distribuidos, OIDC

El ataque de confusión de algoritmo - y cómo prevenirlo

La confusión de algoritmo ocurre cuando un servidor lee el campo `alg` del encabezado JWT para decidir cómo verificar el token, en lugar de forzar el algoritmo desde su propia configuración. Un atacante modifica el encabezado para cambiar `RS256` por `HS256`, y luego firma el token con la clave pública del servidor usada como secreto HMAC. Un servidor mal configurado lo acepta como válido. La solución es una línea de código, pero debe estar presente.

typescript
// ✗ Vulnerable - algorithm inferred from token header
jwt.verify(token, publicKey);

// ✓ Correct - algorithm enforced from server configuration
jwt.verify(token, publicKey, { algorithms: ['RS256'] });

Warning

Nunca omitas la opción `algorithms` en `jwt.verify()`. Aunque tu versión actual de la librería rechace por defecto el algoritmo `none`, listar explícitamente los algoritmos permitidos en tu código deja clara la intención, sobrevive a actualizaciones de la librería y elimina por completo la clase de vulnerabilidad de confusión de algoritmo.

Validación de la fuerza de la clave para HS256

Al usar HS256, el secreto debe tener al menos 256 bits (32 bytes) para coincidir con el tamaño de salida de SHA-256. Secretos cortos - menos de 32 caracteres, palabras de diccionario o cadenas estáticas como `"secret"` o `"development"` - se rompen por fuerza bruta trivialmente con herramientas como `hashcat` o `jwt_tool`. Genera secretos con una fuente aleatoria criptográficamente segura: `crypto.randomBytes(32).toString('hex')` en Node.js produce una cadena hexadecimal de 64 caracteres que cumple el requisito mínimo de entropía.

Validar claims JWT estándar en TypeScript

La especificación JWT define un conjunto de claims registrados estándar que toda implementación debería entender. La librería `jsonwebtoken` valida varios de ellos automáticamente cuando pasas las opciones correctas, pero la clave está en "cuando las pasas". Sin configuración explícita, la mayoría de las comprobaciones de claims se omiten en silencio.

Los claims exp, nbf e iat

El claim exp (expiración) es una marca de tiempo Unix tras la cual el token deja de ser válido. La librería jsonwebtoken comprueba exp por defecto durante jwt.verify(). Sin embargo, la desincronización de relojes entre el emisor del token y el verificador puede hacer que tokens válidos sean rechazados, un origen común de errores de "token expirado" en sistemas distribuidos donde los relojes de los servidores derivan por segundos. Pasa clockTolerance para permitir una ventana pequeña: establecer clockTolerance en 30 acepta tokens hasta 30 segundos después de su valor exp.

typescript
interface JwtPayload {
  sub: string;
  iss: string;
  aud: string;
  exp: number;
  iat: number;
  role: 'admin' | 'user';
}

const payload = jwt.verify(token, publicKey, {
  algorithms: ['RS256'],
  issuer: 'https://auth.example.com',
  audience: 'api.example.com',
  clockTolerance: 30,           // seconds of clock skew to tolerate
}) as JwtPayload;

Los claims iss y aud

El claim `iss` (emisor) identifica el origen del token. El claim `aud` (audiencia) identifica el destinatario previsto. Ambos son opcionales en la especificación JWT pero críticos en la práctica. Sin validación de `iss`, cualquier servicio que pueda producir tokens válidos con tu clave de firma puede autenticarse en tu API. Sin validación de `aud`, un token emitido para tu app móvil puede reutilizarse contra tu API de administración. Pasa ambos como opciones a `jwt.verify()` para que la librería los imponga como requisitos estrictos y no como campos informativos.

Tip

Comprueba los valores `iss` y `aud` de un token que hayas recibido pegándolo en el [Decodificador y Validador JWT](/tools/data/validators/jwt-decoder-and-validator). El payload decodificado muestra todos los claims en un formato legible, lo que facilita confirmar que tus cadenas de emisor y audiencia coinciden con lo que la librería está configurada para esperar.

Implementar la validación JWT en TypeScript

Una función completa de verificación JWT en TypeScript maneja validación criptográfica, validación de claims y clasificación de errores en un solo lugar. Así se estructura, con los cuatro pasos que corresponden al esquema HowTo.

1

Verifica que el algoritmo coincida con tu tipo de clave

Antes de escribir código de verificación, confirma tu combinación de algoritmo y clave. RS256 requiere una clave privada RSA para firmar y la clave pública correspondiente para verificar. HS256 requiere el mismo secreto compartido en ambos lados. Confundirlos provoca excepciones en tiempo de ejecución difíciles de diagnosticar. Guarda tu clave pública o secreto compartido en variables de entorno; nunca los incrustes en archivos fuente.

2

Valida explícitamente los claims exp y nbf

Establece siempre `clockTolerance` para manejar pequeñas derivas de reloj entre servicios. Un valor de 30 segundos es un valor por defecto razonable para la mayoría de los sistemas distribuidos. Al depurar `TokenExpiredError` en producción, registra `payload.exp * 1000` y `Date.now()` juntos: esto muestra exactamente cuántos milisegundos pasó el token de su expiración, lo que distingue una expiración real de un problema de sincronización de relojes entre tu servicio de autenticación y el servidor API.

3

Comprueba los claims iss y aud contra los valores esperados

Pasa las opciones `issuer` y `audience` a `jwt.verify()` para que la librería rechace tokens con valores no coincidentes antes de que se ejecute tu código de aplicación. Si tu sistema tiene múltiples audiencias válidas (por ejemplo, tanto `api.example.com` como `admin.example.com`), pasa un array: `audience: ['api.example.com', 'admin.example.com']`. La librería acepta el token si el claim `aud` coincide con cualquier entrada del array.

4

Prueba tu configuración con el Decodificador JWT

Antes de ejecutar tu suite de pruebas TypeScript, pega un token de muestra de tu entorno de desarrollo o staging en el Decodificador y Validador JWT. Confirma visualmente que cada claim - `alg`, `exp`, `iss`, `aud` y tus claims personalizados - coincide con las opciones de tu `jwt.verify()`. Esta comprobación de un minuto detecta discrepancias entre lo que contiene el token y lo que espera tu código antes de invertir tiempo en depurar en un entorno de pruebas.

Decodificador y Validador JWT

Decodifica tokens JWT e inspecciona todos los claims, campos del encabezado y problemas de seguridad comunes al instante en tu navegador - sin registro, sin subidas al servidor.

Open tool

Errores comunes de configuración JWT

Estos son los errores de configuración que aparecen con más frecuencia en implementaciones JWT de TypeScript. Cada uno es silencioso al arrancar y solo se manifiesta como un fallo de autenticación o un incidente de seguridad en producción.

Usar `jwt.decode()` en lugar de `jwt.verify()`

La función `jwt.decode()` extrae el payload sin verificar la firma. Es útil para inspeccionar un token en el que ya confías - como extraer un ID de usuario de un token ya validado por middleware. No es un sustituto de `jwt.verify()`. El código que usa `jwt.decode()` para obtener claims y luego toma decisiones de autorización basadas en esos claims está aceptando tokens no verificados. Es una omisión completa de la autenticación.

Ignorar el tipo de error en los bloques catch

La librería `jsonwebtoken` lanza tres tipos de error distintos: `JsonWebTokenError` (token malformado o firma inválida), `TokenExpiredError` (pasado el claim `exp`) y `NotBeforeError` (antes del claim `nbf`). Capturar todos los errores como un `Error` genérico y devolver `401 Unauthorized` para todos los casos pierde información de diagnóstico. Maneja cada tipo por separado y devuelve mensajes específicos - `token expirado` frente a `token inválido` - para que los clientes y los sistemas de monitoreo distingan problemas de configuración de intentos de ataque genuinos.

No rotar secretos o pares de claves

Los secretos de firma de larga vida acumulan riesgo con el tiempo. Un secreto que nunca se ha rotado significa que cada token emitido con él sigue siendo válido si el secreto se ve comprometido. Implementa un campo de ID de clave (`kid`) en tu encabezado JWT para que el verificador pueda buscar la clave pública correcta en un endpoint JWKS. Este patrón permite la rotación de claves sin invalidar tokens firmados por la clave anterior: cada token lleva una referencia a la clave específica que lo firmó. El Inspector de JWK ayuda a validar la salida del endpoint JWKS y detectar material de clave privada que no debería estar expuesto públicamente.

Warning

Nunca subas secretos JWT ni claves privadas al control de versiones. Usa variables de entorno para todo el material de claves, cárgalas en tiempo de ejecución y confirma que están establecidas antes de aceptar cualquier solicitud. Una aplicación que arranca con un secreto indefinido o vacío aceptará silenciosamente tokens firmados con una cadena vacía.

Aceptar el algoritmo `none`

El algoritmo `none` produce un JWT sin firma - cualquier payload con estructura válida pasa la verificación. Las primeras versiones de las librerías JWT aceptaban `none` por defecto. Las librerías modernas lo rechazan, pero solo cuando especificas explícitamente los algoritmos permitidos en las opciones de verificación. Incluye siempre `algorithms: ['RS256']` (o tu algoritmo concreto) para hacer explícito el rechazo de `none` y resistir cambios de versión de la librería.

Depurar problemas JWT con herramientas de navegador

Escribir una prueba para reproducir un error JWT suele ser más lento que inspeccionar el token directamente. Las herramientas de navegador te permiten examinar los claims, el estado de expiración y la estructura de claves de un token en segundos, sin entorno local, sin ejecutar código y sin subir datos sensibles a un servicio de terceros.

Decodificar e inspeccionar claims

El Decodificador y Validador JWT decodifica el encabezado y el payload de cualquier cadena JWT y presenta todos los claims en un formato estructurado y legible. Comprueba problemas de seguridad comunes - `exp` ausente, algoritmo débil, `aud` ausente - y los señala con diagnósticos claros. Pega cualquier token de tu entorno de desarrollo, staging o producción y confirma en diez segundos si los claims coinciden con lo que espera tu llamada a `jwt.verify()`.

Diagnosticar problemas de expiración

La Calculadora de Cuenta Atrás de Expiración JWT lee el claim `exp` de cualquier token y muestra la vida útil restante exacta o el tiempo desde la expiración tanto en UTC como en hora local. Cuando un usuario informa de "token expirado" pero tus logs muestran que el token debería seguir siendo válido, pégalo en la calculadora. La comparación de marcas de tiempo a nivel de milisegundo revela si el problema es una expiración genuina, una deriva de reloj entre servicios o un valor `exp` almacenado en milisegundos en lugar de segundos - un bug de factor-1000 sorprendentemente común.

Inspeccionar conjuntos de claves JWKS

Al validar tokens de un proveedor OIDC o de cualquier servicio que publique un endpoint JWKS, el Inspector de JWK analiza y valida la estructura del conjunto de claves. Comprueba que cada clave tenga los campos requeridos (`kty`, `use`, `alg`, `kid`), valida el tipo de clave y la curva para claves EC, y señala cualquier material de clave privada que no debería estar expuesto públicamente. Pega el JSON de tu endpoint JWKS directamente en la herramienta o proporciona la URL para que se obtenga.

Calculadora de Cuenta Atrás de Expiración JWT

Calcula la cuenta atrás exacta de expiración JWT desde el claim exp - mira el tiempo restante o el tiempo desde la expiración en UTC y hora local, sin código.

Open tool

Buenas prácticas de validación JWT

Una función de verificación JWT correctamente configurada es necesaria pero no suficiente para una autenticación segura. Estas prácticas completan el panorama para servicios TypeScript de producción.

Usa una interfaz de payload tipada

Define una interfaz TypeScript para tu payload JWT y convierte el resultado de verificación a ella. Esto te da seguridad en tiempo de compilación sobre nombres de claims y tipos de valores: un nombre de claim mal escrito (`userId` frente a `user_id`) se convierte en un error de TypeScript en lugar de un `undefined` silencioso en tiempo de ejecución. Mantén la interfaz en un módulo de tipos compartido para que sea consistente en todos los servicios que verifican el mismo formato de token.

Vidas cortas de token con refresh tokens

Los tokens de acceso deben tener vidas cortas: de 15 minutos a 1 hora para la mayoría de las APIs. Los tokens de acceso de larga vida (días, semanas) aumentan la ventana durante la cual un token comprometido puede usarse. Usa un flujo separado de refresh token con expiración larga para la persistencia de sesión. El refresh token rota en cada uso, y las listas de revocación solo se necesitan para los refresh tokens - no para los de acceso - cuando las vidas se mantienen cortas.

Centraliza la lógica de verificación

Escribe la verificación JWT en un solo lugar - una función de middleware o una utilidad compartida - y úsala en todas partes. La lógica de verificación duplicada invita a la deriva de configuración: un endpoint comprueba `aud`, otro olvida hacerlo, y la inconsistencia se explota antes de que alguien se dé cuenta. El middleware de Express, los guards de NestJS y los manejadores de rutas de Next.js tienen patrones limpios para centralizar las comprobaciones de autenticación. Pon tus opciones `algorithms`, `issuer` y `audience` en un único objeto de configuración importado en todo el código base.

Configura la verificación una vez, aplícala en todas partes. La única opción JWT que debería diferir entre endpoints es la audiencia esperada.

- Principio de implementación segura de JWT

Tip

Al adoptar un nuevo proveedor de autenticación o actualizar tu librería JWT, usa el [Decodificador y Validador JWT](/tools/data/validators/jwt-decoder-and-validator) para inspeccionar tokens de la nueva fuente antes de actualizar tu configuración de verificación. Esto confirma los valores exactos de `alg`, `iss` y `aud` en los nuevos tokens para que tus cambios de código coincidan con la realidad y no con suposiciones.

Key takeaways

  • Pasa siempre `algorithms: ['RS256']` (o tu algoritmo concreto) explícitamente a `jwt.verify()` - nunca dejes que la librería lo infiera del encabezado del token.
  • Valida los claims `iss` y `aud` en cada llamada de verificación; omitirlos permite que tokens de otros servicios se autentiquen contra tu API.
  • Usa `clockTolerance` para manejar la deriva de relojes entre servicios distribuidos, y registra las marcas de tiempo `exp` junto a `Date.now()` al depurar errores de expiración.
  • Nunca uses `jwt.decode()` para decisiones de autorización - se salta por completo la verificación de firma y acepta cualquier payload de token.
  • El Decodificador y Validador JWT te permite inspeccionar todos los claims y señalar problemas de configuración en segundos, sin escribir ni ejecutar código.
  • RS256 es preferible a HS256 para APIs de producción - elimina el riesgo de distribución de secretos compartidos y soporta rotación de claves basada en JWKS.
  • Mantén vidas cortas de los tokens de acceso (15-60 minutos) y centraliza toda la lógica de verificación en un único middleware o utilidad para prevenir la deriva de configuración.

Preguntas frecuentes

Use the `jsonwebtoken` library (or `jose` for a modern alternative) and call `jwt.verify(token, secret, { algorithms: ['RS256'], issuer: 'your-issuer', audience: 'your-audience' })`. Always specify the `algorithms` array explicitly - never allow the library to infer it from the token header, as this enables algorithm confusion attacks. Wrap the call in a try/catch and handle `JsonWebTokenError`, `TokenExpiredError`, and `NotBeforeError` separately so you can return informative error responses to API clients.

An algorithm confusion attack occurs when a server accepts the `alg` field from the JWT header to determine how to verify the signature, rather than enforcing the algorithm from its own configuration. An attacker can change `alg` from `RS256` to `HS256` in the header, sign the token with the server's public key as the HMAC secret, and the server will incorrectly validate it as legitimate. The fix: always pass `algorithms: ['RS256']` (or your specific algorithm) explicitly in the verify options.

Call `jwt.verify()` - it throws a `TokenExpiredError` if the `exp` claim is in the past. To inspect expiry without throwing, decode the payload with `jwt.decode(token)` and compare `payload.exp * 1000` to `Date.now()`. For a visual expiry check without writing code, paste your token into the Aback Tools JWT Expiry Countdown Calculator, which shows the exact remaining time or time since expiry in both UTC and local time.

Yes - both are critical. The `iss` (issuer) claim identifies who created the token. Without verifying it, your application will accept tokens issued by any service, including attackers. The `aud` (audience) claim identifies the intended recipient. Without verifying it, a token issued for one of your services can be replayed against another. Pass both as options: `{ issuer: 'https://auth.example.com', audience: 'api.example.com' }`.

HS256 (HMAC-SHA256) uses a single shared secret for both signing and verification. It is simpler to implement but requires every service that verifies tokens to hold the same secret - a security risk in distributed systems. RS256 (RSA-SHA256) uses a private key to sign and a public key to verify. Only the issuing service holds the private key; all consuming services use the public key. RS256 is the recommended algorithm for production APIs where tokens are verified by multiple services or third parties.

After `jwt.verify()` succeeds, cast the result to a typed interface and assert your custom claim values. For example: `const payload = jwt.verify(token, secret) as MyPayload; if (payload.role !== 'admin') throw new Error('Insufficient role')`. Using a TypeScript interface for your JWT payload type gives you compile-time safety on claim names and value types. Validate any claim whose absence or wrong value would represent a security failure - not just standard claims.

The `jose` library is a modern, standards-compliant implementation of JWT, JWS, JWE, JWK, and JWKS that works in Node.js, browsers, Deno, and edge runtimes like Cloudflare Workers. Use `jose` when you need JWKS endpoint support for OIDC, when building for edge or serverless environments, or when you need JWE (encrypted JWT) support. Use `jsonwebtoken` for simple HS256 or RS256 signing and verification in traditional Node.js backends where a shared-secret or static key is sufficient.

Paste the JWT into the Aback Tools JWT Decoder and Validator at abacktools.com/tools/data/validators/jwt-decoder-and-validator. It decodes the header and payload, shows all claims in a readable format, checks for common configuration issues, and flags security problems - all in your browser with no server upload. For expiry checks, the JWT Expiry Countdown Calculator shows exactly how much time remains or how long ago the token expired.

ShareXLinkedIn