{"record":{"id":"ac4743c18787814d","repo":"honojs/hono","slug":"invalid-credentials-structure","errorCode":null,"errorMessage":"invalid credentials structure","messagePattern":"invalid credentials structure","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"src/middleware/jwk/jwk.ts","lineNumber":87,"sourceCode":"\n  if (!options || !(options.keys || options.jwks_uri)) {\n    throw new Error('JWK auth middleware requires options for either \"keys\" or \"jwks_uri\" or both')\n  }\n\n  if (!crypto.subtle || !crypto.subtle.importKey) {\n    throw new Error('`crypto.subtle.importKey` is undefined. JWK auth middleware requires it.')\n  }\n\n  return async function jwk(ctx, next) {\n    const headerName = options.headerName || 'Authorization'\n\n    const credentials = ctx.req.raw.headers.get(headerName)\n    let token\n    if (credentials) {\n      const parts = credentials.split(/\\s+/)\n      if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {\n        const errDescription = 'invalid credentials structure'\n        throw new HTTPException(401, {\n          message: errDescription,\n          res: unauthorizedResponse({\n            ctx,\n            error: 'invalid_request',\n            errDescription,\n            realm: options.realm,\n          }),\n        })\n      } else {\n        token = parts[1]\n      }\n    } else if (options.cookie) {\n      if (typeof options.cookie == 'string') {\n        token = getCookie(ctx, options.cookie)\n      } else if (options.cookie.secret) {\n        if (options.cookie.prefixOptions) {\n          token = await getSignedCookie(\n            ctx,","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/middleware/jwk/jwk.ts#L69-L105","documentation":"When an Authorization header is present, the JWK middleware expects exactly the form 'Bearer <token>' (case-insensitive scheme, single space-separated into two parts). Any other structure — missing token, extra segments, or a different scheme — triggers a 401 HTTPException with error 'invalid_request' and description 'invalid credentials structure'.","triggerScenarios":"Requests with headers like 'Authorization: Bearer' (no token), 'Bearer a b c' (extra whitespace-separated parts), 'Basic dXNlcjpwYXNz', or 'token' alone; also custom headerName values where the client sends a non-Bearer format.","commonSituations":"Clients sending Basic auth or API keys to an endpoint expecting JWTs; custom auth schemes when headerName was changed (e.g. a proxy injecting X-Auth-Token with the raw token and no Bearer prefix); malformed hand-rolled client code concatenating tokens incorrectly.","solutions":["Make the client send 'Authorization: Bearer <jwt>' with exactly one space and no extra parts","If using a custom header carrying the raw token, note the middleware still expects the Bearer prefix — either prepend 'Bearer ' client-side or pre-process the header","Return/inspect the WWW-Authenticate response to distinguish this structural 401 from an invalid token","Add a client-side check that the header matches /^Bearer \\S+$/ before sending"],"exampleFix":"// before\nfetch('/api', { headers: { Authorization: token } })\n// after\nfetch('/api', { headers: { Authorization: `Bearer ${token}` } })","handlingStrategy":"validation","validationCode":"const isBearerHeader = (h: string | null): boolean =>\n  !!h && /^bearer\\s+\\S+$/i.test(h)\n// client-side, before fetch:\nif (!isBearerHeader(`Bearer ${token}`)) throw new Error('bad header')","typeGuard":"const isWellFormedBearer = (credentials: string | null | undefined): credentials is string =>\n  !!credentials && credentials.split(/\\s+/).length === 2 && credentials.split(/\\s+/)[0].toLowerCase() === 'bearer'","tryCatchPattern":"try { await fetch(url, { headers: { Authorization: `Bearer ${token}` } }) } catch (e) { if (e instanceof HTTPException && e.status === 401) { /* inspect res body for invalid_request vs invalid_token */ } }","preventionTips":["Always format headers as `Bearer ${token}` with template literals","Never send Basic auth or raw API keys to JWK-protected routes","Add a client-side regex check /^Bearer \\S+$/ before sending","Log the WWW-Authenticate response header to distinguish structural errors from bad tokens"],"tags":["jwk","jwt","authorization-header","http-401","auth"],"backgroundTag":"malformed-authorization-header","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}