-
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.js
with bothcheckSqlAuth
andextendContext
:
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.securityContext
isundefined
inextendContext
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:
checkSqlAuth
returnssecurityContext
→ 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:
contextByReq
receivessecurityContext
as a parameter but never sets it onreq
before 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
securityContext
as a parameter—it just needs to set it onreq
before invokingextendContext