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

错误信息

Unable to find a signing key that matches: "2026-10"

也可能输出为

  • jwt.exceptions.PyJWKClientError: Unable to find a signing key that matches: "2026-10"
  • Unable to find a signing key that matches: "None"

引号中的值是令牌的 `kid`;`"None"` 表示头部中没有 `kid`。

PyJWT (Python) — jwt.exceptions.PyJWKClientError from PyJWKClient.get_signing_key_from_jwt

含义

`PyJWKClient` 获取了密钥集,但没有找到 `kid` 与令牌头部中的 `kid`(即引号中的值)相同的签名密钥。遇到未知的 `kid` 时,PyJWKClient 会刷新一次密钥集,所以这个密钥目前确实没有发布在该 URL 上。引号中的 `"None"` 表示令牌根本没有 `kid`。

原因

修复方法

  1. 1.

    将令牌的 kid 与已加载的密钥对比

    `get_signing_keys(refresh=True)` 会准确显示 PyJWKClient 能使用哪些密钥。如果其中没有令牌的 `kid`,问题就出在颁发者或 URL 上,而不在你的代码。

    python
    print(jwt.get_unverified_header(token).get("kid"))
    for key in client.get_signing_keys(refresh=True):
        print(key.key_id, key.algorithm_name)
  2. 2.

    复用同一个 PyJWKClient

    每次请求都新建客户端等于禁用了缓存,每次调用都会请求颁发者。带有密钥缓存的长期客户端在出现新的 `kid` 时仍会重新获取。

    python
    from jwt import PyJWKClient
    
    # Module level: one client, cached keys, refetch on an unknown kid.
    JWKS = PyJWKClient("https://issuer.example.com/.well-known/jwks.json", cache_keys=True, lifespan=600)
    
    def verify(token: str) -> dict:
        signing_key = JWKS.get_signing_key_from_jwt(token)
        return jwt.decode(token, signing_key.key, algorithms=["ES256"], audience="https://api.example.com")

相关错误

浏览完整的签名错误库