cube-js/cube · error

You cannot change security context via __user from ${session

Error message

You cannot change security context via __user from ${session.user} to ${request.meta.changeUser}, because it's not allowed.

What it means

When a SQL client sends the special __user meta property (session variable in the SQL query) with a different username, Cube tries to switch the security context to that user. Switching is only allowed for superusers or when the canSwitchSqlUser callback permits it; otherwise the SQL server throws this error naming the originating and requested users.

Source

Thrown at packages/cubejs-api-gateway/src/sql-server.ts:121

    const canSwitchSqlUser: CanSwitchSQLUserFn = options.canSwitchSqlUser
      || this.createDefaultCanSwitchSqlUserFn(options);

    const contextByRequest = async (request, session) => {
      let userForContext = session.user;
      let { securityContext } = session;

      if (request.meta.changeUser && request.meta.changeUser !== session.user) {
        const sqlAuthRequest: SqlAuthServiceAuthenticateRequest = {
          protocol: request.meta.protocol,
          method: 'password',
        };
        const canSwitch = session.superuser || await canSwitchSqlUser(session.user, request.meta.changeUser);
        if (canSwitch) {
          userForContext = request.meta.changeUser;
          const current = await checkSqlAuth({ ...request, ...sqlAuthRequest }, userForContext, null);
          securityContext = current.securityContext;
        } else {
          throw new Error(
            `You cannot change security context via __user from ${session.user} to ${request.meta.changeUser}, because it's not allowed.`
          );
        }
      }
      return this.contextByNativeReq(request, securityContext, request.id);
    };

    const canSwitchUserForSession = async (session, user) => session.superuser || canSwitchSqlUser(session.user, user);

    this.sqlInterfaceInstance = await registerInterface({
      gatewayPort: this.gatewayPort,
      pgPort: options.pgSqlPort,
      contextToApiScopes: async ({ securityContext }) => this.apiGateway.contextToApiScopesFn(
        securityContext,
        getEnv('defaultApiScope') || await this.apiGateway.contextToApiScopesDefFn()
      ),
      checkAuth: async ({ request, token }) => {
        const { securityContext } = await this.apiGateway.checkAuthFn(request, token);

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Configure canSwitchSqlUser in SQLServer options to authorize the specific user switch.
  2. Connect with the SQL superuser account (sqlSuperUser) when impersonation via __user is required.
  3. Remove or correct the __user variable in the client's session settings/BI tool configuration so it matches the authenticated user.

Example fix

// before
const server = new SQLServer(apiGateway, { gatewayPort });
// after
const server = new SQLServer(apiGateway, {
  gatewayPort,
  canSwitchSqlUser: async (fromUser, toUser) => toUser.startsWith('tenant_')
});
Defensive patterns

Strategy: try-catch

Validate before calling

const mayImpersonate = async (session, targetUser) =>
  session.superuser || (typeof canSwitchSqlUser === 'function' && await canSwitchSqlUser(session.user, targetUser));
// check mayImpersonate(session, request.meta.changeUser) before sending __user

Type guard

function requestsImpersonation(msg: { meta?: { changeUser?: string, protocol?: string } }, sessionUser: string): boolean {
  return !!msg.meta?.changeUser && msg.meta.changeUser !== sessionUser;
}

Try / catch

try {
  await runSqlWithImpersonation(query, targetUser);
} catch (e) {
  if (e.message.startsWith("You cannot change security context via __user")) {
    console.error(`Impersonation from ${session.user} to ${targetUser} denied; connect as superuser or configure canSwitchSqlUser`);
  } else throw e;
}

Prevention

When it happens

Trigger: A SQL client issues a query whose __user session variable differs from the authenticated SQL user (e.g. `SET __user = 'other'; SELECT ...`) while the authenticated session is not a superuser and no canSwitchSqlUser option authorizes the switch.

Common situations: BI tools configured with a tenant/user template variable that injects __user while connecting as a shared SQL account; developers imitating multi-tenant impersonation without defining canSwitchSqlUser; connecting as a non-superuser account (sqlUser) instead of the superuser (sqlSuperUser) when impersonation is intended.

Related errors


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