Skip to content
ecdsa.com
jose (JavaScript)JWKS and key discovery

Error message

multiple matching keys found in the JSON Web Key Set

jose (JavaScript) — JWKSMultipleMatchingKeys, code ERR_JWKS_MULTIPLE_MATCHING_KEYS

What it means

More than one key in the JSON Web Key Set could verify this token, and jose refuses to guess. This happens when the token header has no `kid` (or several keys share the same `kid`) and the set contains two or more keys of the right type and curve. jose deliberately does not try the candidates for you inside `jwtVerify`; the thrown error is itself an async iterator over the candidate keys, so you can opt in to trying them.

Why it happens

How to fix it

  1. 1.

    Identify the signing key in every token

    The robust fix is on the issuer: give each key a unique `kid` (an RFC 7638 thumbprint works well), publish it in the JWKS, and write it into the protected header of every 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. 2.

    Opt in to trying the candidates

    When you cannot change the issuer, iterate over the error: jose yields each candidate key, and you accept the token only if one of them verifies. This costs one signature check per candidate, so keep the key set small.

    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();
      }
    }

Related errors

Browse the full signature error database