honojs/hono · error · JwtAlgorithmNotAllowed

algorithm "${alg}" is not in the allowed list: [${allowedAlg

Error message

algorithm "${alg}" is not in the allowed list: [${allowedAlgorithms.join(', ')}]

What it means

Thrown by verifyWithJwks when the token header's alg is not in the options.allowedAlgorithms list. This whitelist prevents unexpected or downgrade algorithms from being accepted, independent of key availability.

Source

Thrown at src/utils/jwt/jwt.ts:225

  const verifyOpts = options.verification || {}

  const header = decodeHeader(token)

  if (!isTokenHeader(header)) {
    throw new JwtHeaderInvalid(header)
  }
  if (!header.kid) {
    throw new JwtHeaderRequiresKid(header)
  }

  // Reject symmetric algorithms (HS256, HS384, HS512) to prevent algorithm confusion attacks
  if (symmetricAlgorithms.includes(header.alg as SymmetricAlgorithm)) {
    throw new JwtSymmetricAlgorithmNotAllowed(header.alg)
  }

  // Validate against allowed algorithms
  if (!options.allowedAlgorithms.includes(header.alg as AsymmetricAlgorithm)) {
    throw new JwtAlgorithmNotAllowed(header.alg, options.allowedAlgorithms)
  }

  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[]))

View on GitHub (pinned to e2740d5a1b)

Solutions

  1. Decode the token header to see the actual alg value
  2. Add that alg to allowedAlgorithms (e.g. ['RS256','ES256'])
  3. If the alg is unexpected (e.g. none/HS*), treat it as suspicious and reject
  4. Sync the whitelist with the algorithms your IdP advertises in its JWKS metadata

Example fix

// before
await verifyWithJwks(es256Token, { allowedAlgorithms: ['RS256'], ... })
// after
await verifyWithJwks(es256Token, { allowedAlgorithms: ['RS256', 'ES256'], ... })
Defensive patterns

Strategy: validation

Validate before calling

const header = decodeHeader(token)
if (!allowedAlgorithms.includes(header.alg)) throw new Error(`alg ${header.alg} not allowed`)

Try / catch

try { await verifyWithJwks(token, opts) } catch (e) { if (e instanceof JwtAlgorithmNotAllowed) return unauthorized('alg not allowed'); throw e }

Prevention

When it happens

Trigger: verifyWithJwks(token, { allowedAlgorithms: ['RS256'], ... }) on a token signed with e.g. ES256 or PS256, so the includes() check fails.

Common situations: IdP switched signing algorithm (e.g. RS256 → ES256) after rotation or config change; default allowedAlgorithms not matching the provider; multi-tenant app verifying tokens from providers with different algorithms.

Related errors


AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28). Data as JSON: /api/errors/e8b199ff580cb426. Report an issue: GitHub.