{"record":{"id":"a3b6712eb545d1bb","repo":"cube-js/cube","slug":"api-scope-is-missing-scope","errorCode":null,"errorMessage":"API scope is missing: ${scope}","messagePattern":"API scope is missing: (.+?)","errorType":"http","errorClass":"CubejsHandlerError","httpStatus":403,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":2817,"sourceCode":"          return defaultApiScope;\n        } else {\n          return this.contextToApiScopesDefFn();\n        }\n      };\n  }\n\n  protected async assertApiScope(\n    scope: ApiScopes,\n    securityContext?: any,\n  ): Promise<void> {\n    const scopes =\n      await this.contextToApiScopesFn(\n        securityContext || {},\n        getEnv('defaultApiScope') || await this.contextToApiScopesDefFn(),\n      );\n    const permited = scopes.indexOf(scope) >= 0;\n    if (!permited) {\n      throw new CubejsHandlerError(\n        403,\n        'Forbidden',\n        `API scope is missing: ${scope}`\n      );\n    }\n  }\n\n  protected extractAuthorizationHeaderWithSchema(req: Request) {\n    const authHeader = req.headers?.['x-cube-authorization'] || req.headers?.authorization;\n\n    if (typeof authHeader === 'string') {\n      const parts = authHeader.split(' ', 2);\n      if (parts.length === 1) {\n        return parts[0];\n      }\n\n      return parts[1];\n    }","sourceCodeStart":2799,"sourceCodeEnd":2835,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L2799-L2835","documentation":"Cube enforces API scopes per request: assertApiScope computes the scopes for the request's securityContext (via contextToApiScopes or the default) and throws this 403 Forbidden if the scope required by the endpoint (e.g. 'sql', 'jobs', 'graphql') is not among them. Authentication succeeded; the token's identity simply lacks permission for this API surface.","triggerScenarios":"A request to a scope-gated endpoint (SQL API, jobs API, GraphQL) whose securityContext resolves to scopes that don't include the required scope — e.g. contextToApiScopes returns ['data'] but the client hits /v1/sql or the SQL interface.","commonSituations":"After tightening contextToApiScopes or setting the defaultApiScope env var too narrowly, previously working clients start failing; users with viewer roles attempting to use Cube SQL; tokens without role claims falling into the most restrictive branch.","solutions":["Update contextToApiScopes to grant the missing scope for the relevant securityContexts (add 'sql'/'jobs'/etc. for roles that need it).","Check the defaultApiScope environment variable — if it excludes the scope, either widen it or ensure tokens carry claims mapping to broader scopes.","Verify the request's token actually contains the claims your contextToApiScopes inspects (decode the JWT).","If the client shouldn't use that endpoint, stop calling it (e.g. use the REST data API instead of the SQL API)."],"exampleFix":"// before\ncontextToApiScopes: (ctx) => ['data'],\n// after\ncontextToApiScopes: (ctx) => ctx.role === 'analyst' ? ['data', 'sql'] : ['data'],","handlingStrategy":"validation","validationCode":"async function assertScopeAllowed(securityContext, requiredScope) {\n  const scopes = await contextToApiScopes(securityContext, ['data']);\n  if (!scopes.includes(requiredScope)) {\n    throw new Error(`UI should hide this endpoint: missing scope ${requiredScope}`);\n  }\n}","typeGuard":"function hasScope(scopes, scope) {\n  return Array.isArray(scopes) && scopes.includes(scope);\n}","tryCatchPattern":"try {\n  const result = await cubeApi.sql(); // or jobs/graphql endpoint\n} catch (e) {\n  if (e.status === 403 && /API scope is missing/.test(e.message)) {\n    // token identity lacks this scope; route user to a permitted surface or upgrade their role\n  }\n  throw e;\n}","preventionTips":["Hide gated endpoints (SQL API, jobs) in your app when the user's scopes don't include them","Keep contextToApiScopes logic aligned with role management changes","Write integration tests per role asserting which endpoints succeed","Check the defaultApiScope env var after environment migrations"],"tags":["auth","api-scopes","authorization","forbidden"],"backgroundTag":"missing-api-scope","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}