honojs/hono · error · Error
verifyWithJwks requires options for either "keys" or "jwks_u
Error message
verifyWithJwks requires options for either "keys" or "jwks_uri" or both
What it means
verifyWithJwks was called with options containing neither a non-empty 'keys' array nor a 'jwks_uri'. The function needs at least one source of verification keys, so it fails fast before doing any work.
Source
Thrown at src/utils/jwt/jwt.ts:245
let verifyKeys = options.keys ? [...options.keys] : undefined
if (options.jwks_uri) {
const response = await fetch(options.jwks_uri, init)
if (!response.ok) {
throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`)
}
const data = (await response.json()) as { keys?: JsonWebKey[] }
if (!data.keys) {
throw new Error('invalid JWKS response. "keys" field is missing')
}
if (!Array.isArray(data.keys)) {
throw new Error('invalid JWKS response. "keys" field is not an array')
}
verifyKeys ??= []
verifyKeys.push(...(data.keys as HonoJsonWebKey[]))
} else if (!verifyKeys) {
throw new Error('verifyWithJwks requires options for either "keys" or "jwks_uri" or both')
}
const matchingKey = verifyKeys.find((key) => key.kid === header.kid)
if (!matchingKey) {
throw new JwtTokenInvalid(token)
}
// Verify that JWK's alg matches JWT header's alg when JWK has alg field
if (matchingKey.alg && matchingKey.alg !== header.alg) {
throw new JwtAlgorithmMismatch(matchingKey.alg, header.alg)
}
return await verify(token, matchingKey, {
alg: header.alg,
...verifyOpts,
})
}
View on GitHub (pinned to e2740d5a1b)
Solutions
- Pass at least one of options.keys (non-empty HonoJsonWebKey[]) or options.jwks_uri (string)
- Check for typos in option names and that dynamic config is not undefined
- If keys comes from dynamic filtering, ensure the fallback jwks_uri is included when it ends up empty
Example fix
// before
verifyWithJwks(token, {})
// after
verifyWithJwks(token, { jwks_uri: 'https://auth.example.com/.well-known/jwks.json' }) Defensive patterns
Strategy: validation
Validate before calling
const opts: VerifyJwksOptions = {}
if (jwksUri) opts.jwks_uri = jwksUri
if (keys?.length) opts.keys = keys
if (!opts.jwks_uri && !opts.keys?.length) throw new Error('verification keys not configured')
await verifyWithJwks(token, opts) Type guard
const hasKeySource = (o: { keys?: unknown[]; jwks_uri?: string }) =>
!!o.jwks_uri || (Array.isArray(o.keys) && o.keys.length > 0) Try / catch
try { await verifyWithJwks(token, opts) } catch (e) { if ((e as Error).message.includes('either "keys" or "jwks_uri"')) failStartupConfigCheck(); throw e } Prevention
- Fail fast at boot if neither keys nor jwks_uri is configured
- Type options as VerifyJwksOptions to catch typos at compile time
- Log effective options before first verification
When it happens
Trigger: verifyWithJwks(token, {}) or verifyWithJwks(token, { keys: [] }) with no jwks_uri; or a typo'd option name like { jwkUri: ... } or { key: [...] }.
Common situations: Building options dynamically and passing undefined; renaming options during a refactor; passing an empty keys array after filtering and forgetting the URI fallback.
Related errors
- required "kid" in jwt header: ${JSON.stringify(header)}
- symmetric algorithm "${alg}" is not allowed for JWK verifica
- invalid JWKS response. "keys" field is missing
- invalid JWKS response. "keys" field is not an array
- ${key} must not contain "\r" or "\n"
AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28).
Data as JSON: /api/errors/c2d827a5dfacd02a.
Report an issue: GitHub.