cube-js/cube · error · CubejsHandlerError

Authorization header isn't set

Error message

Authorization header isn't set

What it means

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.

Source

Thrown at packages/cubejs-api-gateway/src/gateway.ts:2715

        return verifyToken(auth, jwk);
      };
    }

    return async (req, auth) => {
      if (auth) {
        try {
          req.securityContext = await checkAuthFn(auth);
          req.signedWithPlaygroundAuthSecret =
            Boolean(internalOptions?.isPlaygroundCheckAuth) && hasDevTokenScope(req.securityContext);
        } catch (e: any) {
          if (this.enforceSecurityChecks) {
            throw new CubejsHandlerError(403, 'Forbidden', 'Invalid token', e);
          }
        }
      } else if (this.enforceSecurityChecks) {
        // @todo Move it to 401 or 400
        throw new CubejsHandlerError(403, 'Forbidden', 'Authorization header isn\'t set');
      }

      return {
        securityContext: req.securityContext
      };
    };
  }

  protected createCheckAuthFn(options: ApiGatewayOptions): PreparedCheckAuthFn {
    const mainCheckAuthFn = options.checkAuth
      ? this.wrapCheckAuth(options.checkAuth)
      : this.createDefaultCheckAuth(options.jwt);

    if (this.playgroundAuthSecret) {
      const systemCheckAuthFn = this.createCheckAuthSystemFn();

      return async (ctx, authorization) => {
        // TODO: separate two auth workflows

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Send the header with every request: `Authorization: Bearer <jwt>` or `x-cube-authorization: Bearer <jwt>`.
  2. Configure the Cube client library with a token or a getToken function so it attaches the header automatically.
  3. Check proxies/ingress (nginx, API gateways, redirects) aren't stripping the Authorization header; re-add it via header forwarding rules.
  4. If requests are redirected (http->https), make sure the client sends the header after the final redirect.

Example fix

// before
curl http://localhost:4000/cubejs-api/v1/load?query=...
// after
curl -H "Authorization: $CUBEJS_TOKEN" http://localhost:4000/cubejs-api/v1/load?query=...
Defensive patterns

Strategy: validation

Validate before calling

function ensureAuthHeader(init = {}) {
  const headers = new Headers(init.headers || {});
  if (!headers.has('Authorization') && !headers.has('x-cube-authorization')) {
    headers.set('Authorization', `Bearer ${getToken()}`);
  }
  return { ...init, headers };
}
fetch('/cubejs-api/v1/load', ensureAuthHeader({ method: 'POST', body }));

Type guard

function hasAuthorizationHeader(headers) {
  return Boolean(headers && (headers['authorization'] || headers['x-cube-authorization']));
}

Try / catch

try {
  await cubeApi.load(query);
} catch (e) {
  if (e.status === 403 && e.message.includes('Authorization header')) {
    // client misconfiguration: attach token then retry once
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/4e1009bd9cd26fce. Report an issue: GitHub.