Hello,
I am wondering how to create a JWT web token and pass it to my rest API call. I am trying to pass a securityContext object to Cube.dev, as detailed in their documentation here:
However, I cannot seem to import jwt
using this line:
const jwt = require("jsonwebtoken");
When I do, I receive this following error.
My full WIP code:
// docs: https://cube.dev/docs/product/auth/context
const jwt = require("jsonwebtoken");
const CUBE_API_SECRET = retoolContext.configVars.env_var_cube_rest_api_authorization_token;
const cubeToken = jwt.sign({ user_id: 42 }, CUBE_API_SECRET, {
expiresIn: "30d",
});
return cubeToken;
Answer
I can't make a new comment with the answer so I am editing my original question.
For anyone curious, we eventually solved this in the following way.
Generate JWT token
A problem is that we cannot import the jsonwebtoken
package within the retool app. Interestingly enough, we can do it within resources. However, in our case this wasn't helpful, as we needed information from the user to pass into the JWT's payload for authentication.
The solution was instead to make a function with equivalent functionality to the package. We put it in a transformer:
// Helper function to convert a string to base64url
function base64urlEncode(input) {
return CryptoJS.enc.Base64.stringify(input)
.replace(/=/g, "") // Remove padding
.replace(/\+/g, "-") // Replace '+' with '-'
.replace(/\//g, "_"); // Replace '/' with '_'
}
// Function to generate JWT
function generateJWT(payload, secret, expiresIn = "30d") {
// Header: {"alg":"HS256","typ":"JWT"}
const header = {
alg: "HS256",
typ: "JWT"
};
// Add expiration to the payload
const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
const exp = expiresIn === "30d" ? currentTime + 30 * 24 * 60 * 60 : currentTime + 60; // Default to 30 days
payload.exp = exp;
// Encode header and payload
const encodedHeader = base64urlEncode(CryptoJS.enc.Utf8.parse(JSON.stringify(header)));
const encodedPayload = base64urlEncode(CryptoJS.enc.Utf8.parse(JSON.stringify(payload)));
// Create the signing input
const signingInput = `${encodedHeader}.${encodedPayload}`;
// Generate the signature using HMAC-SHA256
const signature = CryptoJS.HmacSHA256(signingInput, secret);
// Base64url encode the signature
const encodedSignature = base64urlEncode(signature);
// Concatenate the final JWT
return `${signingInput}.${encodedSignature}`;
}
Then we used the function like this.
// Usage
const CUBE_API_SECRET = {{ retoolContext.configVars.env_var_cube_js_api_secret }};
const payload = { projectId: {{ supabase_config_of_organization.data.organization_conformed_source_gcp_project_id[0] }} };
const jwt = generateJWT(payload, CUBE_API_SECRET);
return jwt;
With the JWT now generated, we could pass it into the headers of the query if we defined the headers at the query level (within the app) instead of the resource level.