honojs/hono · error · Error
JWK auth middleware requires options for either "keys" or "j
Error message
JWK auth middleware requires options for either "keys" or "jwks_uri" or both
What it means
The JWK auth middleware requires at least one source of verification keys: either static 'keys' (an array of JWKs / a JWKS), a 'jwks_uri' to fetch keys from, or both. If neither is present in the options object, construction fails immediately with this error.
Source
Thrown at src/middleware/jwk/jwk.ts:71
allow_anon?: boolean
cookie?:
| string
| { key: string; secret?: string | BufferSource; prefixOptions?: CookiePrefixOptions }
headerName?: string
alg: AsymmetricAlgorithm[]
realm?: string
verification?: VerifyOptions
},
init?: RequestInit
): MiddlewareHandler => {
const verifyOpts = options.verification || {}
if (!options || !(options.keys || options.jwks_uri)) {
throw new Error('JWK auth middleware requires options for either "keys" or "jwks_uri" or both')
}
if (!crypto.subtle || !crypto.subtle.importKey) {
throw new Error('`crypto.subtle.importKey` is undefined. JWK auth middleware requires it.')
}
return async function jwk(ctx, next) {
const headerName = options.headerName || 'Authorization'
const credentials = ctx.req.raw.headers.get(headerName)
let token
if (credentials) {
const parts = credentials.split(/\s+/)
if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {
const errDescription = 'invalid credentials structure'
throw new HTTPException(401, {
message: errDescription,
res: unauthorizedResponse({View on GitHub (pinned to e2740d5a1b)
Solutions
- Pass options.keys (JWKS/JWK array) or options.jwks_uri (e.g. your IdP's https://.../jwks.json endpoint)
- If keys come from env/config, validate at startup that at least one source resolves to a truthy value before creating the middleware
- Check spelling: the field is jwks_uri (snake_case), not jwksUri or jwksUrl
- If you fetch keys dynamically, point jwks_uri at the issuer's JWKS endpoint rather than passing a fetched array conditionally
Example fix
// before
app.use('/api/*', jwk({ realm: 'api' }))
// after
app.use('/api/*', jwk({ jwks_uri: 'https://issuer.example.com/.well-known/jwks.json', realm: 'api' })) Defensive patterns
Strategy: type-guard
Validate before calling
const hasKeySource = (o: { keys?: unknown; jwks_uri?: string } | undefined): boolean =>
!!o && (!!o.keys || !!o.jwks_uri)
if (!hasKeySource(opts)) throw new Error('JWK config incomplete') Type guard
interface JwkOpts { keys?: unknown[]; jwks_uri?: string }
const hasJwkKeySource = (o: JwkOpts | undefined): o is Required<Pick<JwkOpts,'keys'|'jwks_uri'>> & JwkOpts =>
!!o && (!!o.keys || !!o.jwks_uri) Try / catch
try { app.use(jwk(opts)) } catch (e) { if (e instanceof Error && /keys.*jwks_uri/.test(e.message)) { /* fail startup with clear config error */ } throw e } Prevention
- Fail fast at boot: assert keys or jwks_uri is present before creating the middleware
- Type the options object so keys/jwks_uri are explicit, not conditionally undefined
- Double-check the exact field name jwks_uri (snake_case)
- Put a startup smoke test that constructs the middleware in CI
When it happens
Trigger: Calling jwk() with an empty options object, only a 'realm'/'headerName' setting, or only cookie options — i.e., omitting both options.keys and options.jwks_uri.
Common situations: Loading keys conditionally from env and accidentally passing undefined (e.g. keys: process.env.JWKS ? JSON.parse(...) : undefined) when the env var is missing; typos like 'key' or 'jwksUrl'; refactors that moved key config into a nested 'verification' object, which does not count as the key source.
Related errors
- invalid credentials structure
- no authorization included in request
- Unauthorized
- basic auth middleware requires options for "username and pas
- bearer auth middleware requires options for "token" or "veri
AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28).
Data as JSON: /api/errors/e62b215d6b51e3f9.
Report an issue: GitHub.