Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions services/cubejs/src/utils/checkSqlAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,33 @@ const buildSqlSecurityContext = (sqlCredentials) => {

/**
* Check SQL authentication for a user.
*
* Cube.js v1.6 invokes this callback as `checkSqlAuth(request, user, password)`
* (see @cubejs-backend/api-gateway/dist/src/sql-server.js — the callback is
* wrapped with three positional args). Earlier builds passed a single object
* `{ username, password }`; the defensive branches below keep backward-
* compatibility with that older shape.
*
* Supports two authentication methods:
* 1. WorkOS JWT as password (new): password is a JWT, username is datasource ID
* 2. Legacy sql_credentials lookup (existing): username/password from sql_credentials table
* 1. WorkOS / FraiOS JWT as password: password is a JWT, username is the datasource ID
* 2. Legacy sql_credentials lookup: username/password from the sql_credentials table
*
* @param {null} _ - Unused parameter.
* @param {Object} user - The user object with username and password.
* @returns {Promise} - Resolves to { password, securityContext }
* @param {Object} request - Cube.js SQL request metadata (protocol, method, apiType)
* @param {string|Object} userArg - Username string (v1.6+) or legacy { username, password } object
* @param {string} [passwordArg] - Password string (v1.6+); absent in legacy object-shape calls
* @returns {Promise<{ password: string, securityContext: Object }>}
*/
const checkSqlAuth = async (_, user) => {
const password = typeof user === "string" ? user : user?.password;
const username = typeof user === "string" ? _ : user?.username;

// Detect if password looks like a JWT (WorkOS RS256)
const checkSqlAuth = async (request, userArg, passwordArg) => {
// Resolve the two shapes Cube has used for this callback:
// new: (request, username: string, password: string)
// legacy: (_req, { username, password })
const username =
typeof userArg === "string" ? userArg : userArg?.username;
const password =
passwordArg ??
(typeof userArg === "string" ? undefined : userArg?.password);

// Detect if password looks like a JWT (WorkOS RS256 / FraiOS HS256)
if (password && password.includes(".") && password.split(".").length === 3) {
const tokenType = detectTokenType(password);

Expand Down Expand Up @@ -134,8 +148,12 @@ const checkSqlAuth = async (_, user) => {
}
}

// Legacy sql_credentials path (unchanged)
const sqlCredentials = await findSqlCredentials(username || user);
// Legacy sql_credentials path — lookup by the plaintext username.
// Cube.js compares the supplied password against `password` in the return value.
if (!username || typeof username !== "string") {
throw new Error("Incorrect user name or password");
}
const sqlCredentials = await findSqlCredentials(username);

return {
password: sqlCredentials?.password,
Expand Down
Loading