{"record":{"id":"e8b199ff580cb426","repo":"honojs/hono","slug":"algorithm-alg-is-not-in-the-allowed-list","errorCode":null,"errorMessage":"algorithm \"${alg}\" is not in the allowed list: [${allowedAlgorithms.join(', ')}]","messagePattern":"algorithm \"(.+?)\" is not in the allowed list: \\[(.+?)\\]","errorType":"exception","errorClass":"JwtAlgorithmNotAllowed","httpStatus":null,"severity":"error","filePath":"src/utils/jwt/jwt.ts","lineNumber":225,"sourceCode":"  const verifyOpts = options.verification || {}\n\n  const header = decodeHeader(token)\n\n  if (!isTokenHeader(header)) {\n    throw new JwtHeaderInvalid(header)\n  }\n  if (!header.kid) {\n    throw new JwtHeaderRequiresKid(header)\n  }\n\n  // Reject symmetric algorithms (HS256, HS384, HS512) to prevent algorithm confusion attacks\n  if (symmetricAlgorithms.includes(header.alg as SymmetricAlgorithm)) {\n    throw new JwtSymmetricAlgorithmNotAllowed(header.alg)\n  }\n\n  // Validate against allowed algorithms\n  if (!options.allowedAlgorithms.includes(header.alg as AsymmetricAlgorithm)) {\n    throw new JwtAlgorithmNotAllowed(header.alg, options.allowedAlgorithms)\n  }\n\n  let verifyKeys = options.keys ? [...options.keys] : undefined\n\n  if (options.jwks_uri) {\n    const response = await fetch(options.jwks_uri, init)\n    if (!response.ok) {\n      throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`)\n    }\n    const data = (await response.json()) as { keys?: JsonWebKey[] }\n    if (!data.keys) {\n      throw new Error('invalid JWKS response. \"keys\" field is missing')\n    }\n    if (!Array.isArray(data.keys)) {\n      throw new Error('invalid JWKS response. \"keys\" field is not an array')\n    }\n    verifyKeys ??= []\n    verifyKeys.push(...(data.keys as HonoJsonWebKey[]))","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/utils/jwt/jwt.ts#L207-L243","documentation":"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.","triggerScenarios":"verifyWithJwks(token, { allowedAlgorithms: ['RS256'], ... }) on a token signed with e.g. ES256 or PS256, so the includes() check fails.","commonSituations":"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.","solutions":["Decode the token header to see the actual alg value","Add that alg to allowedAlgorithms (e.g. ['RS256','ES256'])","If the alg is unexpected (e.g. none/HS*), treat it as suspicious and reject","Sync the whitelist with the algorithms your IdP advertises in its JWKS metadata"],"exampleFix":"// before\nawait verifyWithJwks(es256Token, { allowedAlgorithms: ['RS256'], ... })\n// after\nawait verifyWithJwks(es256Token, { allowedAlgorithms: ['RS256', 'ES256'], ... })","handlingStrategy":"validation","validationCode":"const header = decodeHeader(token)\nif (!allowedAlgorithms.includes(header.alg)) throw new Error(`alg ${header.alg} not allowed`)","typeGuard":null,"tryCatchPattern":"try { await verifyWithJwks(token, opts) } catch (e) { if (e instanceof JwtAlgorithmNotAllowed) return unauthorized('alg not allowed'); throw e }","preventionTips":["Keep allowedAlgorithms in sync with the IdP's advertised algorithms","Include all legitimate algorithms your multi-tenant providers use"],"tags":["jwt","algorithm-whitelist","security"],"backgroundTag":"jwt-algorithm-not-allowed","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}