Mensaje de error
jwt signature is required
jsonwebtoken (Node.js) — JsonWebTokenError from jwt.verify()
Qué significa
El tercer segmento del token está vacío —es un JWT no protegido (`alg: "none"`) o un token firmado al que se le cortó la firma—, pero llamas a `verify()` con una clave, así que la firma es obligatoria. jsonwebtoken lo rechaza antes que aceptar claims (declaraciones) que nadie firmó. Si tokens así llegan a tu API desde fuera, puede que alguien esté sondeando la clásica debilidad «alg none».
Por qué ocurre
Un token no protegido con alg «none»
frecuenteEl RFC 7519 permite JWT sin firmar en contextos donde la integridad se garantiza por otros medios; una API nunca es uno de esos contextos. Un token como `eyJhbGciOiJub25lIn0.eyJzdWIiOiJhZG1pbiJ9.` puede atribuirse la identidad que quiera.
Tokens construidos a mano en pruebas o herramientas
ocasionalLos datos de prueba montados codificando en base64 un encabezado y una carga útil, o los tokens que generan las herramientas de depuración con la firma desactivada, tienen la firma vacía.
La firma se perdió por el camino
ocasionalUn filtro que enmascara datos en los registros, un límite de longitud de URL o una columna de almacenamiento que cortan el token justo después del segundo punto dejan un encabezado y una carga útil de aspecto válido sin nada que verificar.
Cómo solucionarlo
- 1.
Mantener el rechazo y la lista de algoritmos permitidos
Verifica con una lista `algorithms` explícita que nombre solo los algoritmos que usa tu emisor. Registra el origen de la solicitud si llegan tokens sin firmar desde fuera; no añadas una ruta de código que los acepte.
js // Always pass an explicit allow-list; "none" must never be in it. const claims = jwt.verify(token, publicKey, { algorithms: ["ES256"] }); - 2.
Firmar los tokens de prueba con una clave desechable
Genera un par de claves en la preparación de las pruebas y firma con él los datos de prueba, para que las pruebas recorran la misma ruta de verificación que en producción.
js import { generateKeyPairSync } from "node:crypto"; // Test setup: a throwaway key pair, real signatures, same verification path as production. const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" }); const token = jwt.sign({ sub: "test-user" }, privateKey, { algorithm: "ES256", expiresIn: "5m" });