Сообщение об ошибке
missing required "aud" claim
Также выводится как
- missing required "iss" claim
- missing required "exp" claim
- missing required "sub" claim
- missing required "iat" claim
Имя утверждения в сообщении зависит от того, какого утверждения нет (`"aud"`, `"iss"`, `"exp"`, `"sub"`, `"iat"`…). В `err.claim` содержится это имя, а `err.reason` равен `"missing"`.
jose (JavaScript) — JWTClaimValidationFailed, code ERR_JWT_CLAIM_VALIDATION_FAILED, reason "missing"
Что это означает
В токене нет утверждения, которое ваши параметры проверки делают обязательным. jose считает утверждение обязательным не только когда вы перечисляете его в `requiredClaims`, но и всякий раз, когда вы просите его проверить: `audience` требует `aud`, `issuer` — `iss`, `subject` — `sub`, а `maxTokenAge` — `iat`. Имя утверждения в кавычках показывает, какого именно не хватает; подпись к этому моменту уже признана верной.
Почему это происходит
Параметр проверки подразумевает это утверждение
частоПараметр `audience: "https://api.example.com"` означает «токен должен быть выпущен для этого API». Токен без `aud` не может этому соответствовать, поэтому jose сообщает, что утверждения нет, вместо того чтобы молча пропустить токен. То же относится к `issuer`, `subject` и `maxTokenAge`.
Издатель вообще не записывает это утверждение
частоСамописные или внутренние сервисы выдачи токенов часто не добавляют `aud` или `exp`. У токенов без `exp` срок действия не истекает никогда, а токены без `aud` можно повторно предъявить любому сервису, который доверяет тому же издателю. И то и другое стоит исправить у источника.
Утверждение перечислено в requiredClaims
иногда`requiredClaims: ["exp", "jti"]` делает эти утверждения обязательными независимо от их значений. Токены того типа, где одного из них законно нет (например, долгоживущий служебный токен без `exp`), здесь отклоняются, и так задумано.
До проверяющей стороны дошёл токен другого типа
иногдаТокены обновления, токены выхода и специфичные для провайдера токены — тоже JWT, но содержат другие наборы утверждений. Если набор утверждений выглядит незнакомым, значит, отправлен не тот токен.
Как исправить
- 1.
Записывайте в лог недостающее утверждение и те, что есть в токене
У объекта ошибки есть свойства `claim`, `reason` и декодированный `payload`. Если записать их в лог, уже по одному запросу видно, что произошло: «издатель не записывает утверждение» или «отправлен не тот токен».
js import { errors, jwtVerify } from "jose"; try { await jwtVerify(token, jwks, { algorithms: ["ES256"], audience: "https://api.example.com" }); } catch (err) { if (err instanceof errors.JWTClaimValidationFailed && err.reason === "missing") { console.error("token lacks claim:", err.claim, "claims present:", Object.keys(err.payload)); } throw err; } - 2.
Пусть издатель добавляет это утверждение
Лучше исправить токен, чем смягчать проверку. Именно `aud`, `iss` и `exp` делают JWT безопасным для приёма; RFC 8725 рекомендует включать их в каждый токен.
js import { SignJWT } from "jose"; const token = await new SignJWT({ scope: "orders:read" }) .setProtectedHeader({ alg: "ES256", kid }) .setIssuer("https://issuer.example.com") .setAudience("https://api.example.com") // the claim the verifier requires .setIssuedAt() .setExpirationTime("10m") .sign(privateKey);