{"record":{"id":"4e1009bd9cd26fce","repo":"cube-js/cube","slug":"authorization-header-isn-t-set","errorCode":null,"errorMessage":"Authorization header isn't set","messagePattern":"Authorization header isn't set","errorType":"http","errorClass":"CubejsHandlerError","httpStatus":403,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":2715,"sourceCode":"\n        return verifyToken(auth, jwk);\n      };\n    }\n\n    return async (req, auth) => {\n      if (auth) {\n        try {\n          req.securityContext = await checkAuthFn(auth);\n          req.signedWithPlaygroundAuthSecret =\n            Boolean(internalOptions?.isPlaygroundCheckAuth) && hasDevTokenScope(req.securityContext);\n        } catch (e: any) {\n          if (this.enforceSecurityChecks) {\n            throw new CubejsHandlerError(403, 'Forbidden', 'Invalid token', e);\n          }\n        }\n      } else if (this.enforceSecurityChecks) {\n        // @todo Move it to 401 or 400\n        throw new CubejsHandlerError(403, 'Forbidden', 'Authorization header isn\\'t set');\n      }\n\n      return {\n        securityContext: req.securityContext\n      };\n    };\n  }\n\n  protected createCheckAuthFn(options: ApiGatewayOptions): PreparedCheckAuthFn {\n    const mainCheckAuthFn = options.checkAuth\n      ? this.wrapCheckAuth(options.checkAuth)\n      : this.createDefaultCheckAuth(options.jwt);\n\n    if (this.playgroundAuthSecret) {\n      const systemCheckAuthFn = this.createCheckAuthSystemFn();\n\n      return async (ctx, authorization) => {\n        // TODO: separate two auth workflows","sourceCodeStart":2697,"sourceCodeEnd":2733,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L2697-L2733","documentation":"The checkAuth middleware requires an Authorization header (or x-cube-authorization). When no header is present at all and security checks are enforced, Cube throws this 403 Forbidden — the request never reached token verification. The code comments that 401/400 would be more appropriate, but the shipped status is 403.","triggerScenarios":"Calling any Cube REST/GraphQL endpoint without setting `Authorization: <token>` (or `x-cube-authorization`); a proxy or API gateway stripping the Authorization header before forwarding; using a client library instance without a `token`/jwt configured.","commonSituations":"Browser CORS preflight/redirect dropping custom headers; requests sent through an ingress that sanitizes Authorization; forgetting to configure the token in @cubejs-client after env changes; curl tests that omit the header entirely.","solutions":["Send the header with every request: `Authorization: Bearer <jwt>` or `x-cube-authorization: Bearer <jwt>`.","Configure the Cube client library with a token or a getToken function so it attaches the header automatically.","Check proxies/ingress (nginx, API gateways, redirects) aren't stripping the Authorization header; re-add it via header forwarding rules.","If requests are redirected (http->https), make sure the client sends the header after the final redirect."],"exampleFix":"// before\ncurl http://localhost:4000/cubejs-api/v1/load?query=...\n// after\ncurl -H \"Authorization: $CUBEJS_TOKEN\" http://localhost:4000/cubejs-api/v1/load?query=...","handlingStrategy":"validation","validationCode":"function ensureAuthHeader(init = {}) {\n  const headers = new Headers(init.headers || {});\n  if (!headers.has('Authorization') && !headers.has('x-cube-authorization')) {\n    headers.set('Authorization', `Bearer ${getToken()}`);\n  }\n  return { ...init, headers };\n}\nfetch('/cubejs-api/v1/load', ensureAuthHeader({ method: 'POST', body }));","typeGuard":"function hasAuthorizationHeader(headers) {\n  return Boolean(headers && (headers['authorization'] || headers['x-cube-authorization']));\n}","tryCatchPattern":"try {\n  await cubeApi.load(query);\n} catch (e) {\n  if (e.status === 403 && e.message.includes('Authorization header')) {\n    // client misconfiguration: attach token then retry once\n  }\n  throw e;\n}","preventionTips":["Configure token injection once in the Cube client (token/getToken) instead of per-request","Add an interceptor/middleware that rejects outgoing requests lacking an Authorization header","Audit proxies and gateways for header stripping; forward Authorization explicitly","Prefer x-cube-authorization when intermediaries touch the standard Authorization header"],"tags":["auth","http-headers","forbidden","missing-credentials"],"backgroundTag":"missing-authorization-header","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}