Сообщение об ошибке
no applicable key found in the JSON Web Key Set
jose (JavaScript) — JWKSNoMatchingKey, code ERR_JWKS_NO_MATCHING_KEY
Что это означает
jose просмотрела переданный ей набор ключей JSON Web Key Set и не нашла ни одного ключа, которым разрешено проверять этот токен. Ключ подходит, только если выполнены все условия: его `kid` равен `kid` из заголовка токена (если он там есть), его `kty` соответствует `alg` токена, его `alg` (если задан) равен `alg` токена, его `crv` совпадает с нужным (P-256 для ES256), `use` отсутствует или равен `"sig"`, а `key_ops` (если задан) содержит `"verify"`. Никаких криптографических операций не выполнялось — сбой произошёл при выборе ключа.
Почему это происходит
Издатель провёл ротацию ключа подписи
частоВ новых токенах стоит новый `kid`, которого ещё нет в закешированном или жёстко прописанном в коде наборе ключей. Это самая частая причина, и обычно сбои начинаются ровно в минуту ротации: сервисы, перезапущенные после неё, работают, а запущенные раньше выдают ошибку.
Набор ключей принадлежит другому издателю или окружению
частоURL JWKS из staging-окружения в рабочей среде, JWKS другого тенанта или набор ключей, скопированный из документации. Каждый `kid` выглядит правдоподобно, но ни один не совпадает.
Метаданные ключа противоречат токену
иногдаВ JWK указан `alg: "RS256"`, а токен подписан алгоритмом ES256, или EC-ключ лежит на кривой P-384, а токен использует ES256 (для него нужна P-256). jose пропускает такие ключи, даже если `kid` совпадает: метаданные JWK существуют именно для того, чтобы ключ не использовали с другим алгоритмом.
Ключ помечен как ключ шифрования
иногдаЕсли ключ опубликован с `use: "enc"` или с `key_ops` без `"verify"`, это не ключ проверки подписи. Некоторые провайдеры публикуют ключи обоих видов в одном наборе; проверять токены можно только ключами `sig`.
Локальную копию JWKS ни разу не обновляли
иногда`createLocalJWKSet` использует переданные ему ключи бессрочно. Если набор взяли из файла или переменной окружения при развёртывании, со следующей ротацией он незаметно устареет.
Как исправить
- 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.
Загружайте 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.
Публикуйте ключи с согласованными метаданными
Если издателем управляете вы, убедитесь, что у каждого ключа подписи уникальный `kid`, `use: "sig"`, а `alg` и `crv` соответствуют токенам, которые он подписывает. Публикуйте новый ключ до того, как начнёте им подписывать.
json { "keys": [ { "kty": "EC", "crv": "P-256", "kid": "2026-10", "use": "sig", "alg": "ES256", "x": "…", "y": "…" } ] }
Связанные ошибки
multiple matching keys found in the JSON Web Key Setjose (JavaScript)Unable to find a signing key that matches '2026-10-rotated'jwks-rsa (Node.js)IDX10503: Signature validation failed. The token's kid is: '2026-10', but did n…Microsoft.IdentityModel.JsonWebTokens / System.IdentityModel.Tokens.Jwt (.NET)signature verification failedjose (JavaScript)