-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
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:
- Configure
cube.jswith bothcheckSqlAuthandextendContext:
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
}
};- Connect to Cube via SQL API:
psql -h localhost -p 5432 -U myuser -d db - Execute any query:
SELECT * FROM Orders LIMIT 1; - Observe the logs showing
req.securityContextisundefinedinextendContext
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:
checkSqlAuthreturnssecurityContext→ stored insession.securityContext(sql-server.ts:130-139)- On each query:
contextByRequest(request, session)→ receivessession.securityContext(sql-server.ts:91-112) - Calls
contextByNativeReq(request, securityContext, requestId)(sql-server.ts:111) - Calls
apiGateway.contextByReq(req, securityContext, requestId)(sql-server.ts:389) - BUG HERE:
contextByReqreceivessecurityContextas a parameter but never sets it onreqbefore callingextendContext(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
securityContextas a parameter—it just needs to set it onreqbefore invokingextendContext