Message d’erreur
multiple matching keys found in the JSON Web Key Set
jose (JavaScript) — JWKSMultipleMatchingKeys, code ERR_JWKS_MULTIPLE_MATCHING_KEYS
Ce que cela signifie
Plus d’une clé du jeu de clés (JSON Web Key Set) pourrait vérifier ce jeton, et jose refuse de deviner. Cela se produit lorsque l’en-tête du jeton n’a pas de `kid` (ou que plusieurs clés partagent le même `kid`) et que le jeu contient au moins deux clés du bon type et de la bonne courbe. jose n’essaie volontairement pas les candidates à votre place dans `jwtVerify` ; l’erreur levée est elle-même un itérateur asynchrone sur les clés candidates, ce qui vous permet de choisir explicitement de les essayer.
Pourquoi cela se produit
L’émetteur ne met pas de kid dans l’en-tête du jeton
fréquenteDe nombreux émetteurs modestes ou développés maison signent uniquement avec `{ "alg": "ES256" }`. Tant que le JWKS ne contient qu’une seule clé, cela fonctionne ; la première rotation qui publie une deuxième clé casse tous les vérificateurs.
Les clés publiées n’ont pas de kid
fréquenteMême si les jetons portent un `kid`, un JWKS dont les clés n’ont pas de `kid` ne permet aucune correspondance par identifiant. Pendant une rotation, un tel jeu contient la clé sortante et la clé entrante, toutes deux également plausibles.
Deux clés partagent le même kid
occasionnelleCertains scripts de gestion des clés dérivent le `kid` d’un nom fixe ou de l’algorithme (`"es256"`) au lieu de la clé elle-même : l’ancienne et la nouvelle clé se retrouvent alors avec le même identifiant. Les empreintes RFC 7638 évitent ce problème.
Comment corriger l’erreur
- 1.
Identifier la clé de signature dans chaque jeton
La correction robuste se fait côté émetteur : attribuez à chaque clé un `kid` unique (une empreinte RFC 7638 convient bien), publiez-le dans le JWKS et inscrivez-le dans l’en-tête protégé de chaque jeton.
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.
Choisir explicitement d’essayer les clés candidates
Si vous ne pouvez pas modifier l’émetteur, itérez sur l’erreur : jose fournit chaque clé candidate, et vous n’acceptez le jeton que si l’une d’elles le vérifie. Cela coûte une vérification de signature par candidate : gardez donc le jeu de clés réduit.
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(); } }