Mensaje de error
multiple matching keys found in the JSON Web Key Set
jose (JavaScript) — JWKSMultipleMatchingKeys, code ERR_JWKS_MULTIPLE_MATCHING_KEYS
Qué significa
Más de una clave del conjunto de claves JSON Web Key podría verificar este token, y jose se niega a adivinar. Ocurre cuando el encabezado del token no tiene `kid` (o varias claves comparten el mismo `kid`) y el conjunto contiene dos o más claves del tipo y la curva correctos. jose, a propósito, no prueba las candidatas por ti dentro de `jwtVerify`; el error lanzado es en sí un iterador asíncrono sobre las claves candidatas, así que puedes optar explícitamente por probarlas.
Por qué ocurre
El emisor no pone kid en el encabezado del token
frecuenteMuchos emisores pequeños o escritos a mano firman solo con `{ "alg": "ES256" }`. Mientras el JWKS contenga una sola clave, funciona; la primera rotación que publica una segunda clave rompe todos los verificadores.
Las claves publicadas no tienen kid
frecuenteAunque los tokens lleven un `kid`, en un JWKS cuyas claves no tienen `kid` no se puede buscar la coincidencia por identificador. Durante una rotación, un conjunto así contiene la clave saliente y la entrante, ambas igual de plausibles.
Dos claves comparten el mismo kid
ocasionalAlgunos scripts de gestión de claves derivan el `kid` de un nombre fijo o del algoritmo (`"es256"`) en lugar de la propia clave, así que la clave antigua y la nueva acaban con el mismo identificador. Las huellas digitales del RFC 7638 lo evitan.
Cómo solucionarlo
- 1.
Identificar la clave de firma en cada token
La solución robusta está en el emisor: da a cada clave un `kid` único (una huella digital del RFC 7638 funciona bien), publícalo en el JWKS y escríbelo en el encabezado protegido de cada token.
js import { SignJWT } from "jose"; // Issuer side: name the key in every token, and publish the same kid in the JWKS. const token = await new SignJWT(claims) .setProtectedHeader({ alg: "ES256", kid: "2026-10" }) .setExpirationTime("10m") .sign(privateKey); - 2.
Optar por probar las candidatas
Si no puedes cambiar el emisor, itera sobre el error: jose devuelve cada clave candidata y aceptas el token solo si una de ellas lo verifica. Esto cuesta una comprobación de firma por candidata, así que mantén pequeño el conjunto de claves.
js import { errors, jwtVerify } from "jose"; async function verifyWithCandidates(token, jwks, options) { try { return await jwtVerify(token, jwks, options); } catch (err) { if (err?.code !== "ERR_JWKS_MULTIPLE_MATCHING_KEYS") throw err; for await (const publicKey of err) { try { return await jwtVerify(token, publicKey, options); } catch (inner) { if (inner?.code === "ERR_JWS_SIGNATURE_VERIFICATION_FAILED") continue; throw inner; } } throw new errors.JWSSignatureVerificationFailed(); } }