跳到主要内容
ecdsa.com
jose (JavaScript)JWKS 与密钥发现

错误信息

no applicable key found in the JSON Web Key Set

jose (JavaScript) — JWKSNoMatchingKey, code ERR_JWKS_NO_MATCHING_KEY

含义

jose 查遍了你提供的 JSON Web 密钥集,没有找到可以用来验证这个令牌的密钥。只有同时满足以下所有条件的密钥才符合要求:`kid` 等于令牌头部的 `kid`(如果令牌中有的话);`kty` 与令牌的 `alg` 相符;`alg`(如果存在)等于令牌的 `alg`;`crv` 匹配(ES256 对应 P-256);`use` 不存在或为 `"sig"`;`key_ops`(如果存在)包含 `"verify"`。这里没有执行任何密码学运算——失败发生在密钥选择阶段。

原因

修复方法

  1. 1.

    把令牌的 kid 与已发布的密钥对比

    解码受保护头部,并列出已发布的密钥及其 `kid`、`alg`、`kty`、`crv` 和 `use`。如果密钥集中没有这个 `kid`,问题就出在轮换或用错了密钥集;如果有,就检查元数据字段。

    bash
    # kid and alg the token asks for
    python3 -c 'import base64,json,sys; h=sys.argv[1].split(".")[0]; print(json.loads(base64.urlsafe_b64decode(h + "=" * (-len(h) % 4))))' "$TOKEN"
    # kid, alg, kty, crv, use of every key the issuer publishes
    curl -s https://issuer.example.com/.well-known/jwks.json | jq '.keys[] | {kid, alg, kty, crv, use}'
  2. 2.

    获取颁发者的 JWKS,而不是固定密钥

    `createRemoteJWKSet` 会缓存密钥,并在令牌指定了它没见过的 `kid` 时重新获取密钥集,因此能自动跟上轮换,同时又不会接受任意密钥。

    js
    import { createRemoteJWKSet, jwtVerify } from "jose";
    
    // Fetches the JWKS, caches it, and refetches when a token names an unknown kid
    // (at most once per cooldownDuration, 30 s by default).
    const jwks = createRemoteJWKSet(new URL("https://issuer.example.com/.well-known/jwks.json"));
    const { payload } = await jwtVerify(token, jwks, {
      algorithms: ["ES256"],
      issuer: "https://issuer.example.com",
    });
  3. 3.

    发布元数据一致的密钥

    如果颁发者由你运营,确保每个签名密钥都有唯一的 `kid`、`use: "sig"`,以及与它所签名的令牌相符的 `alg` 和 `crv`。先发布新密钥,再开始用它签名。

    json
    {
      "keys": [
        { "kty": "EC", "crv": "P-256", "kid": "2026-10", "use": "sig", "alg": "ES256",
          "x": "…", "y": "…" }
      ]
    }

相关错误

浏览完整的签名错误库