Errores comunes con JWT: exp, nbf, aud, iss y clock skew (y cómo solucionarlos)
Los JWT (JSON Web Tokens) simplifican la autenticación en aplicaciones y APIs, pero también son una fuente común de errores sutiles y difíciles de diagnosticar. Este artículo te guiará a través de los problemas más frecuentes relacionados con la expiración (exp), la fecha de "no antes" (nbf), la audiencia (aud), el emisor (iss) y el desfase de reloj (clock skew), proporcionando soluciones prácticas para evitar dolores de cabeza.
Para seguir los ejemplos y validar tus JWT, te recomiendo tener a mano el Validador / Analizador de JWT, una herramienta que te permite decodificar y analizar los claims sin depender de logs o configuraciones complejas. También te sugiero tener a mano el Validador de JSON para verificar la estructura de tus payloads y el Generador de Hash para comparar firmas y verificar la integridad de los datos.
1. ¿Por qué fallan los JWT? Respuesta directa y soluciones rápidas
Los errores JWT suelen ser el resultado de una configuración incorrecta, desfases de tiempo, o una mala comprensión de cómo funcionan los claims. Aquí tienes las causas más comunes y sus soluciones:
- Expiración (
exp) incorrecta: Asegúrate de que la expiración se maneja correctamente en segundos UTC y considera el clock skew. - Fecha de "no antes" (
nbf) problemática: Usanbfcon moderación y sincroniza los relojes de los servidores. - Audiencia (
aud) incorrecta: Verifica que la audiencia del token coincida con el servicio que lo recibe. - Emisor (
iss) erróneo: Configura el emisor correctamente para cada entorno (desarrollo, pruebas, producción). - Desfase de reloj (clock skew): Sincroniza los relojes de los servidores y configura la tolerancia en las librerías JWT.
- Errores de firma: Verifica el secreto, el algoritmo y la integridad del token.
2. Paso a paso: Cómo solucionar los errores más comunes de JWT
A continuación, te mostramos cómo solucionar cada uno de estos errores, paso a paso:
2.1. Expiración (exp)
El claim exp define cuándo expira el token. Los errores más comunes ocurren por una mala interpretación del formato o la falta de consideración por el desfase de reloj.
- Verifica el formato:
expdebe ser un timestamp en segundos desde la época Unix (UTC). Usa el Validador / Analizador de JWT para asegurarte de que el valor es correcto. - Usa UTC: Asegúrate de que el servidor que genera el token y el que lo valida usen UTC para evitar problemas con las zonas horarias.
- Implementa tolerancia: Configura una tolerancia de tiempo (clock tolerance o leeway) en la librería JWT. Esto permite que los tokens sean válidos por unos segundos más allá de la fecha de expiración, para compensar el desfase de reloj entre los servidores. Por ejemplo, 60 segundos es un valor común.
- Ejemplo Node.js (jsonwebtoken):
jwt.verify(token, 'tu_secreto', { algorithms: ['HS256'], clockTolerance: 60, // Tolerancia de 60 segundos }); - Ejemplo Python (PyJWT):
import jwt try: decoded_token = jwt.decode(token, 'tu_secreto', algorithms=['HS256'], options={"leeway": 60}) # Tolera 60 segundos except jwt.ExpiredSignatureError: print("El token ha expirado") except jwt.InvalidTokenError: print("Token inválido")
2.2. Fecha de "no antes" (nbf)
El claim nbf indica la fecha y hora a partir de la cual el token es válido. Es menos común que exp, pero puede causar problemas si no se gestiona correctamente.
- Sincroniza los relojes: Asegúrate de que todos los servidores que emiten y validan tokens estén sincronizados con NTP (Network Time Protocol).
- Usa
nbfcon precaución: Si no necesitas una activación precisa, considera usarexpen su lugar.nbfintroduce una complejidad adicional y puede generar problemas si los relojes no están sincronizados. - Considera el clock skew: Si usas
nbf, asegúrate de configurar la tolerancia de tiempo en la librería JWT, de la misma forma que conexp. - Ejemplo Node.js (jsonwebtoken):
jwt.verify(token, 'tu_secreto', { algorithms: ['HS256'], clockTolerance: 60, // Tolerancia de 60 segundos }); - Ejemplo Python (PyJWT):
import jwt try: decoded_token = jwt.decode(token, 'tu_secreto', algorithms=['HS256'], options={"leeway": 60}) # Tolera 60 segundos except jwt.ExpiredSignatureError: print("El token ha expirado") except jwt.InvalidTokenError: print("Token inválido")
2.3. Audiencia (aud)
El claim aud especifica a quién va dirigido el token (la audiencia). Es crucial para evitar que un token emitido para un servicio se utilice en otro.
- Define una convención clara: Usa una cadena de texto o un array para definir la audiencia. Documenta la convención para que todos los servicios la entiendan.
- Valida en todos los servicios: Cada servicio debe validar que el token que recibe tiene la audiencia correcta.
- Ejemplo Node.js (jsonwebtoken):
jwt.verify(token, 'tu_secreto', { algorithms: ['HS256'], audience: 'api.servicio-x', // Audiencia esperada }); - Ejemplo Python (PyJWT):
import jwt try: decoded_token = jwt.decode(token, 'tu_secreto', algorithms=['HS256'], audience='api.servicio-x') except jwt.InvalidAudienceError: print("Audiencia inválida") except jwt.InvalidTokenError: print("Token inválido")
2.4. Emisor (iss)
El claim iss identifica al emisor del token (el servidor de autenticación). Es importante para asegurar que los tokens provengan de una fuente confiable.
- Parametriza el emisor: No hardcodees el emisor en el código. Usa variables de entorno o archivos de configuración para definir el emisor para cada entorno (desarrollo, pruebas, producción).
- Valida contra una lista blanca: Valida que el emisor del token coincida con uno de los emisores permitidos.
- Ejemplo Node.js (jsonwebtoken):
jwt.verify(token, 'tu_secreto', { algorithms: ['HS256'], issuer: 'https://auth.miempresa.com', // Emisor esperado }); - Ejemplo Python (PyJWT):
import jwt try: decoded_token = jwt.decode(token, 'tu_secreto', algorithms=['HS256'], issuer='https://auth.miempresa.com') except jwt.InvalidIssuerError: print("Emisor inválido") except jwt.InvalidTokenError: print("Token inválido")
2.5. Desfase de reloj (clock skew)
El clock skew es la diferencia de tiempo entre los relojes de los servidores. Afecta a exp, nbf y, en menor medida, a iat (Issued At).
- Sincroniza los relojes: Asegúrate de que todos los servidores estén sincronizados con NTP. Configura NTP en tus servidores y contenedores.
- Configura la tolerancia: Define la tolerancia de tiempo (clock tolerance o leeway) en las librerías JWT. Esto permite que los tokens sean válidos incluso si hay un pequeño desfase de tiempo.
- Ejemplo Node.js (jsonwebtoken):
jwt.verify(token, 'tu_secreto', { algorithms: ['HS256'], clockTolerance: 60, // Tolerancia de 60 segundos }); - Ejemplo Python (PyJWT):
import jwt try: decoded_token = jwt.decode(token, 'tu_secreto', algorithms=['HS256'], options={"leeway": 60}) # Tolera 60 segundos except jwt.ExpiredSignatureError: print("El token ha expirado") except jwt.InvalidTokenError: print("Token inválido")
2.6. Errores de firma
Los errores de firma suelen ser causados por problemas con el secreto, el algoritmo de firma o la integridad del token.
- Verifica el secreto: Asegúrate de que el secreto sea el correcto y que no contenga espacios en blanco ni caracteres invisibles.
- Verifica el algoritmo: Asegúrate de que el algoritmo de firma sea el correcto (por ejemplo, HS256, RS256).
- Verifica la integridad del token: Comprueba que el token no haya sido truncado. Compara la longitud del token en origen y destino.
- Usa el Validador / Analizador de JWT: Esta herramienta te permite verificar la firma, decodificar el payload y detectar errores de formato.
- Usa el Generador de Hash: Genera un hash del "signing input" (header + "." + payload) y compara. Si el hash difiere, el contenido firmado difiere. Si el hash coincide y la firma no, el problema suele ser el secret o el algoritmo.
3. Checklist accionable para la resolución de problemas JWT
Utiliza esta lista de verificación para solucionar problemas de JWT de forma rápida y eficiente:
- [ ] Verifica el formato del token: Utiliza el Validador / Analizador de JWT para decodificar el token y verificar que es un JWT válido.
- [ ] Comprueba la expiración (
exp): Verifica la fecha de expiración y asegúrate de que sea correcta y que la librería JWT esté configurada con la tolerancia adecuada. - [ ] Revisa la fecha de "no antes" (
nbf): Si se usa, comprueba que la fecha sea correcta y que los relojes estén sincronizados. - [ ] Valida la audiencia (
aud): Asegúrate de que el token sea válido para el servicio que lo está recibiendo. - [ ] Verifica el emisor (
iss): Confirma que el token fue emitido por el emisor correcto. - [ ] Comprueba la firma: Verifica que la firma del token sea válida y que el secreto y el algoritmo sean correctos.
- [ ] Verifica los relojes: Asegúrate de que los servidores estén sincronizados con NTP.
- [ ] Revisa los logs: Busca mensajes de error que puedan indicar el problema.
- [ ] Utiliza herramientas de depuración: Usa el Validador / Analizador de JWT, el Validador de JSON y el Generador de Hash para diagnosticar y solucionar problemas.
4. Errores comunes y sus soluciones
Aquí tienes una tabla que resume los errores más comunes y sus soluciones:
| Error | Causa | Solución |
|---|---|---|
Token expirado (exp) |
Tiempo de expiración incorrecto, desfase de reloj, formato incorrecto. | Verifica el formato, usa UTC, configura clock tolerance. |
Token no válido aún (nbf) |
Relojes no sincronizados, configuración incorrecta. | Sincroniza los relojes, usa nbf con precaución. |
Audiencia inválida (aud) |
Audiencia no coincide con el servicio. | Valida la audiencia, define una convención clara. |
Emisor inválido (iss) |
Emisor incorrecto. | Configura el emisor correctamente, valida contra una lista blanca. |
| Firma inválida | Secreto incorrecto, algoritmo incorrecto, token truncado. | Verifica el secreto, el algoritmo y la integridad del token. |
| Desfase de reloj | Relojes de servidores no sincronizados. | Sincroniza los relojes con NTP, configura clock tolerance. |
5. FAQ: Preguntas frecuentes sobre errores JWT
5.1. ¿Por qué mi token JWT parece válido, pero la API lo rechaza?
La razón más probable es que la audiencia (aud) del token no coincide con la audiencia esperada por la API. También puede ser un problema de emisor (iss), o que el token haya expirado (exp) y la tolerancia configurada no sea suficiente. Utiliza el Validador / Analizador de JWT para inspeccionar los claims del token.
5.2. ¿Cómo puedo saber si el problema es el desfase de reloj?
Si los errores son intermitentes (la misma solicitud funciona a veces y a veces no), el desfase de reloj es un sospechoso habitual. Revisa los logs de los servidores y comprueba si hay diferencias significativas en la hora. Verifica la configuración de NTP en tus servidores.
5.3. ¿Qué es el clock skew y por qué es importante?
El clock skew es la diferencia de tiempo entre los relojes de los servidores. Es importante porque afecta a la validación de los claims exp y nbf. Si los relojes no están sincronizados, los tokens pueden ser rechazados prematuramente (exp) o aceptados antes de tiempo (nbf).
5.4. ¿Qué debo hacer si veo un error de "firma inválida"?
Verifica el secreto que estás utilizando para validar el token. Asegúrate de que no haya espacios en blanco ni caracteres invisibles. Comprueba el algoritmo de firma y asegúrate de que coincide con el algoritmo utilizado para firmar el token. Comprueba que el token no esté truncado. Si sigues teniendo problemas, utiliza el Generador de Hash para comparar el hash del "signing input" y verificar si los datos firmados son los mismos.
6. Tabla comparativa: Librerías JWT más populares
Esta tabla te muestra las librerías JWT más populares y sus características principales. Recuerda elegir la librería que mejor se adapte a tu lenguaje de programación y a las necesidades de tu proyecto.
| Librería | Lenguaje | Características |
|---|---|---|
jsonwebtoken |
Node.js | Sencilla, popular, buena documentación. |
PyJWT |
Python | Robusta, compatible con RFC 7519, fácil de usar. |
jose4j |
Java | Completa, compatible con múltiples algoritmos y estándares. |
FirebaseUI |
Multiplataforma | Implementación frontend y backend, fácil integración con servicios de Google. |
7. Recomendación final según tu caso de uso
La elección de la solución ideal depende de tu contexto:
- Si eres un desarrollador frontend: Concéntrate en entender cómo se generan y se reciben los tokens JWT. Valida los tokens en el cliente solo para propósitos de UI. Utiliza la librería específica de tu framework (Angular, React, Vue, etc.) y presta atención a la gestión segura de los tokens en el almacenamiento local o cookies.
- Si eres un desarrollador backend: Implementa una validación exhaustiva de los tokens. Asegúrate de validar la firma, la expiración, la audiencia y el emisor. Usa variables de entorno para configurar el secreto y el emisor. Utiliza una librería JWT robusta y bien documentada.
- Si estás integrando múltiples servicios: Define una convención clara para los claims y asegúrate de que todos los servicios la cumplen. Utiliza un gateway o proxy para centralizar la validación de los tokens y simplificar la gestión.
- Si estás en un entorno de alta seguridad: Considera implementar medidas adicionales de seguridad, como la rotación de claves, el uso de tokens de corta duración y la revocación de tokens.
En resumen, la clave para evitar errores JWT es la disciplina: define claims de forma clara, sincroniza los relojes, valida estrictamente los tokens y utiliza las herramientas adecuadas para diagnosticar y solucionar los problemas.