Сообщение об ошибке
Expected 200 OK from the JSON Web Key Set HTTP response
jose (JavaScript) — JOSEError from createRemoteJWKSet, code ERR_JOSE_GENERIC
Что это означает
`createRemoteJWKSet` запросил URL набора ключей и получил HTTP-статус, отличный от 200. jose загружает JWKS с отключёнными перенаправлениями (`redirect: "manual"`), поэтому 301/302 считается ошибкой так же, как 404 или 401. Ни один ключ не загружен, и ни одна подпись токена не проверена: по заданному вами URL набор ключей не отдаётся.
Почему это происходит
Заданный URL — не jwks_uri
частоУ каждого провайдера свой путь: Auth0 — `/.well-known/jwks.json`, Keycloak — `/realms/<realm>/protocol/openid-connect/certs`, Entra ID — `/<tenant>/discovery/v2.0/keys`, Google — `https://www.googleapis.com/oauth2/v3/certs`. Если указать в jose URL издателя или адрес самого документа обнаружения, вернётся 404 или ответ не в формате JWKS.
Эндпоинт отвечает перенаправлением
частоПеренаправление с HTTP на HTTPS, перенаправление на адрес с косой чертой в конце или CDN, переместивший файл, отвечают кодом 30x. Браузеры и curl молча переходят по ним, а jose — нет, поэтому URL должен быть конечным.
Набор ключей закрыт аутентификацией или сетевой политикой
иногдаВнутренние поставщики удостоверений иногда находятся за API-шлюзом, который требует учётные данные (401/403), или прокси для исходящего трафика отвечает собственной страницей ошибки. JWKS — открытые данные, и его следует делать доступным без учётных данных для любой проверяющей стороны.
Слишком много запросов
редкоПроверяющая сторона, которая на каждый запрос создаёт новый объект удалённого JWKS, каждый раз заново загружает набор и может получить отказ из-за ограничения частоты запросов (429). Создайте объект один раз и используйте его повторно, чтобы работал его кеш.
Как исправить
- 1.
Берите jwks_uri из документа обнаружения
Провайдеры OpenID Connect публикуют точный URL набора ключей в поле `jwks_uri` документа `/.well-known/openid-configuration`. Получите его один раз при запуске и передайте этот URL в `createRemoteJWKSet`.
js import { createRemoteJWKSet } from "jose"; // Resolve jwks_uri from the provider's discovery document instead of guessing it. const discovery = await fetch("https://login.example.com/.well-known/openid-configuration").then((r) => r.json()); const jwks = createRemoteJWKSet(new URL(discovery.jwks_uri)); - 2.
Проверьте код статуса, не переходя по перенаправлениям
curl без `-L` ведёт себя так же, как jose. Нужен ответ 200 с `{"keys":[...]}`; ответ 30x подсказывает, какой URL указать вместо заданного.
bash # Status line and redirect target, without following redirects (jose does not follow them either) curl -sS -o /dev/null -w '%{http_code} %{redirect_url}\n' https://login.example.com/jwks curl -s https://login.example.com/.well-known/openid-configuration | jq -r .jwks_uri