Skip to content

extendContext cannot access securityContext from checkSqlAuth #10049

@morford-brex

Description

@morford-brex

Describe the bug

The extendContext function cannot access session.securityContext that was returned by checkSqlAuth or checkAuth. When extendContext is called, req.securityContext is always undefined, even though the authentication functions successfully returned a security context. This makes it impossible to implement authentication-method-specific logic in extendContext or to augment the security context based on authenticated user information.

To Reproduce

Steps to reproduce the behavior:

  1. Configure cube.js with both checkSqlAuth and extendContext:
module.exports = {
  checkSqlAuth: (req, user, password) => {
    console.log('checkSqlAuth - setting securityContext');
    return {
      password,
      securityContext: {
        tenantId: 'tenant_123',
        userId: user
      }
    };
  },
  
  extendContext: (req) => {
    console.log('extendContext - securityContext:', req.securityContext);
    // This will log: undefined
  }
};
  1. Connect to Cube via SQL API: psql -h localhost -p 5432 -U myuser -d db
  2. Execute any query: SELECT * FROM Orders LIMIT 1;
  3. Observe the logs showing req.securityContext is undefined in extendContext

Expected behavior

The securityContext returned by checkSqlAuth should be available on req.securityContext when extendContext is called. This would allow:

  • Detecting which authentication method was used (SQL vs JWT)
  • Accessing authenticated user information from the previous auth step
  • Augmenting the context based on authentication type

Expected log output:

checkSqlAuth - setting securityContext
extendContext - securityContext: { tenantId: 'tenant_123', userId: 'myuser' }

Screenshots

N/A

Minimally reproducible Cube Schema

// cube.js
module.exports = {
  checkSqlAuth: (req, user, password) => {
    if (user === 'testuser' && (!password || password === 'testpass')) {
      console.log('checkSqlAuth: Authenticated, returning securityContext');
      return {
        password: 'testpass',
        securityContext: {
          tenantId: 'tenant_abc123',
          userId: user,
          role: 'admin'
        }
      };
    }
    throw new Error('Access denied');
  },
  
  extendContext: (req) => {
    console.log('extendContext: req.securityContext =', req.securityContext);
    // should be { tenantId: 'tenant_abc123', ... }
    
    const protocol = req.meta?.protocol;
    
    if (protocol === 'postgres') {
      // Cannot access the tenantId from checkSqlAuth!
      return {
        securityContext: {
          tenantId: req.securityContext?.tenantId || 'UNKNOWN',  // Always UNKNOWN
        }
      };
    }
    
    // JWT handling...
    const { sub } = req.securityContext || {};
    if (!sub) {
      throw new Error('Missing JWT subject');
    }
    
    return {
      securityContext: {
        ...req.securityContext,
        parsed: true
      }
    };
  }
};

// Schema
cube(`Orders`, {
  sql: `
    SELECT 1 as id, 100 as amount, 'new' as status
    UNION ALL
    SELECT 2 as id, 200 as amount, 'processed' as status
  `,
  
  measures: {
    count: {
      type: `count`,
    }
  },
  
  dimensions: {
    status: {
      sql: `status`,
      type: `string`,
    }
  }
});

Version:

All versions supporting extendContext (v0.28.0+)

Additional context

The issue manifests in packages/cubejs-api-gateway/src/gateway.ts (line ~2160), but the root cause stems from how securityContext flows through the SQL API:

  1. checkSqlAuth returns securityContext → stored in session.securityContext (sql-server.ts:130-139)
  2. On each query: contextByRequest(request, session) → receives session.securityContext (sql-server.ts:91-112)
  3. Calls contextByNativeReq(request, securityContext, requestId) (sql-server.ts:111)
  4. Calls apiGateway.contextByReq(req, securityContext, requestId) (sql-server.ts:389)
  5. BUG HERE: contextByReq receives securityContext as a parameter but never sets it on req before calling extendContext(req) (gateway.ts:2160-2170)

The fix should be in gateway.ts at the contextByReq method because:

  • It's the common code path for REST API, SQL API, and WebSocket subscriptions
  • Fixing at the gateway level ensures consistency across all API types
  • The method already receives securityContext as a parameter—it just needs to set it on req before invoking extendContext

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions