Skip to content

Commit ed6915a

Browse files
acmeguyclaude
andauthored
fix(cubejs): match checkSqlAuth callback signature to Cube.js v1.6 (#41)
Cube.js v1.6 invokes checkSqlAuth as (request, user, password) — three positional args — see @cubejs-backend/api-gateway/dist/src/sql-server.js:291,105. Our implementation declared (_, user) and did: password = typeof user === "string" ? user : user?.password username = typeof user === "string" ? _ : user?.username With the v1.6 wire server, user arrives as a plain string (the Postgres username), so the code took the username as the password AND used the request metadata object as the username. findSqlCredentials then received the {protocol, method, apiType} object, and Hasura rejected the query with: parsing Text failed, expected String, but encountered Object path: $.selectionSet.sql_credentials.args.where.username._eq Every SQL API login failed before any password comparison ran (reproduced via `psql -U <valid> -h <cubejs>` → 28P01). Fix: match the documented v1.6 signature and keep a defensive branch for the legacy object-shape call. Also reject non-string username early so the Hasura GraphQL layer cannot receive a non-string variable. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e8a353b commit ed6915a

1 file changed

Lines changed: 30 additions & 12 deletions

File tree

‎services/cubejs/src/utils/checkSqlAuth.js‎

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,33 @@ const buildSqlSecurityContext = (sqlCredentials) => {
3636

3737
/**
3838
* Check SQL authentication for a user.
39+
*
40+
* Cube.js v1.6 invokes this callback as `checkSqlAuth(request, user, password)`
41+
* (see @cubejs-backend/api-gateway/dist/src/sql-server.js — the callback is
42+
* wrapped with three positional args). Earlier builds passed a single object
43+
* `{ username, password }`; the defensive branches below keep backward-
44+
* compatibility with that older shape.
45+
*
3946
* Supports two authentication methods:
40-
* 1. WorkOS JWT as password (new): password is a JWT, username is datasource ID
41-
* 2. Legacy sql_credentials lookup (existing): username/password from sql_credentials table
47+
* 1. WorkOS / FraiOS JWT as password: password is a JWT, username is the datasource ID
48+
* 2. Legacy sql_credentials lookup: username/password from the sql_credentials table
4249
*
43-
* @param {null} _ - Unused parameter.
44-
* @param {Object} user - The user object with username and password.
45-
* @returns {Promise} - Resolves to { password, securityContext }
50+
* @param {Object} request - Cube.js SQL request metadata (protocol, method, apiType)
51+
* @param {string|Object} userArg - Username string (v1.6+) or legacy { username, password } object
52+
* @param {string} [passwordArg] - Password string (v1.6+); absent in legacy object-shape calls
53+
* @returns {Promise<{ password: string, securityContext: Object }>}
4654
*/
47-
const checkSqlAuth = async (_, user) => {
48-
const password = typeof user === "string" ? user : user?.password;
49-
const username = typeof user === "string" ? _ : user?.username;
50-
51-
// Detect if password looks like a JWT (WorkOS RS256)
55+
const checkSqlAuth = async (request, userArg, passwordArg) => {
56+
// Resolve the two shapes Cube has used for this callback:
57+
// new: (request, username: string, password: string)
58+
// legacy: (_req, { username, password })
59+
const username =
60+
typeof userArg === "string" ? userArg : userArg?.username;
61+
const password =
62+
passwordArg ??
63+
(typeof userArg === "string" ? undefined : userArg?.password);
64+
65+
// Detect if password looks like a JWT (WorkOS RS256 / FraiOS HS256)
5266
if (password && password.includes(".") && password.split(".").length === 3) {
5367
const tokenType = detectTokenType(password);
5468

@@ -134,8 +148,12 @@ const checkSqlAuth = async (_, user) => {
134148
}
135149
}
136150

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

140158
return {
141159
password: sqlCredentials?.password,

0 commit comments

Comments
 (0)