Сообщение об ошибке
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`.
Почему это происходит
Ключ подписи сменили до того, как опубликовали
частоЕсли издатель начинает подписывать новым ключом до того, как добавил его в JWKS (или CDN отдаёт устаревшую копию JWKS), проверяющие стороны не могут найти этот ключ. Издателям следует сначала опубликовать новый ключ и переключаться на него после того, как истечёт срок жизни кешей.
Клиент обращается к набору ключей другого издателя
частоURL JWKS для конкретных тенантов (пулы пользователей Cognito, тенанты Auth0, realm в Keycloak, тенанты Entra ID) похожи друг на друга. URL из другого окружения возвращает настоящие ключи — только не те, которыми подписан этот токен.
В заголовке токена нет kid
иногда`PyJWKClient.get_signing_key_from_jwt` ищет ключ строго по `kid`. Для токенов от издателей, которые его не указывают, ключ так не найти; вместо этого явно проверяйте токен единственным опубликованным ключом.
Ключ есть, но не годится как ключ подписи
иногдаPyJWKClient рассматривает только ключи, у которых `use` отсутствует или равен `"sig"` и которые PyJWT может загрузить; ключ неподдерживаемого типа пропускается. Если `kid` есть в исходном JSON, но не в `get_signing_keys()`, причина в этом.
Как исправить
- 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.
Используйте один общий 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")