Access control
Cube supports a few methods to authenticates requests to APIs & integrations. Usually, an API supports authentication via one of these methods:
- User name and password (e.g., used by the SQL API).
- Identity provider (e.g., used by the Cube Cloud for Sheets).
- Access token (e.g., used by the REST API).
Regardless of the method, the authentication flow includes the following steps:
- User identity information (e.g., password or access token) is passed to Cube.
- Cube validates the identity information or trusts the identity provider.
- User identity information is optionally enriched with additional attributes, such the user's role, via authentication integration.
- Finally, the API request is associated with a security context. It is then used to configure member-level security and row-level security as well as set data access policies.
User name and password
Some visualization tools (e.g., BI tools) can pass user name and, sometimes, password to Cube.
Configuration
Relevant configuration options: check_sql_auth
and can_switch_sql_user
.
Relevant environment variables: CUBEJS_SQL_USER
, CUBEJS_SQL_PASSWORD
, CUBEJS_SQL_SUPER_USER
.
Identity provider
Some visualization tools (e.g., Cube Cloud for Sheets) implement an OAuth 2.0 flow to authenticate users.
OAuth 2.0 flow is available in Cube Cloud on Premium and above (opens in a new tab) product tiers.
During this flow, users are redirected to a login page of an identity provider (e.g., Google) where they enter their credentials. Then, the identity provider passes the user identity information to Cube Cloud.
This method does not require any configuration.
Access token
Some visualization tools (e.g., custom front-end applications) can pass access tokens based on the JSON Web Token (opens in a new tab) (JWT) standard to Cube. These tokens can be either generated by these applications or obtained from an identity provider. Cube then validates these tokens.
The diagram below shows how it works during the request processing in Cube:
Configuration
Relevant configuration options: check_auth
and jwt
.
Relevant environment variables: CUBEJS_API_SECRET
, CUBEJS_JWT_KEY
, CUBEJS_JWK_URL
,
CUBEJS_JWT_AUDIENCE
, CUBEJS_JWT_ISSUER
, CUBEJS_JWT_SUBJECT
, CUBEJS_JWT_CLAIMS_NAMESPACE
.
Custom authentication
Cube allows you to provide your own JWT verification logic. You can use the
check_auth
configuration option to verify a JWT and set the security context.
For example, if you needed to retrieve user information from an LDAP server, you might do the following:
module.exports = {
checkAuth: async (req, auth) => {
try {
const userInfo = await getUserFromLDAP(req.get("X-LDAP-User-ID"))
return { security_context: userInfo }
}
catch {
throw new Error("Could not authenticate user from LDAP")
}
}
}
A typical use case would be:
- A web server serves a page which needs to communicate with the Cube API.
- The web server generates a JWT. The server includes the token in the page or provides the token to the frontend via an XHR request. The token is then stored in the local storage or a cookie.
- The token is used for calls to the Cube API.
- The token is received by Cube, and verified using any available JWKS (if configured)
- Once decoded, the token claims are injected into the security context.
In development mode, the token is not required for authorization, but you can still use it to pass a security context.
Generating JSON Web Tokens
Authentication tokens are generated based on your API secret. Cube CLI generates
an API Secret when a project is scaffolded and saves this value in the .env
file as CUBEJS_API_SECRET
.
You can generate two types of tokens:
- Without security context, which will mean that all users will have the same data access permissions.
- With security context, which will allow you to implement role-based security models where users will have different levels of access to data.
It is considered best practice to use an exp
expiration claim to limit the
lifetime of your public tokens. Learn more in the JWT docs (opens in a new tab).
You can find a library to generate JWTs for your programming language here (opens in a new tab).
In Node.js, the following code shows how to generate a token which will expire
in 30 days. We recommend using the jsonwebtoken
package for this.
const jwt = require("jsonwebtoken");
const CUBE_API_SECRET = "secret";
const cubeToken = jwt.sign({}, CUBE_API_SECRET, { expiresIn: "30d" });
Then, in a web server or cloud function, create a route which generates and returns a token. In general, you will want to protect the URL that generates your token using your own user authentication and authorization:
app.use((req, res, next) => {
if (!req.user) {
res.redirect("/login");
return;
}
next();
});
app.get("/auth/cubejs-token", (req, res) => {
res.json({
// Take note: Cube expects the JWT payload to contain an object!
token: jwt.sign(req.user, process.env.CUBEJS_API_SECRET, {
expiresIn: "1d",
}),
});
});
Then, on the client side, (assuming the user is signed in), fetch a token from the web server:
let apiTokenPromise;
const cubeApi = cube(
() => {
if (!apiTokenPromise) {
apiTokenPromise = fetch(`${API_URL}/auth/cubejs-token`)
.then((res) => res.json())
.then((r) => r.token);
}
return apiTokenPromise;
},
{
apiUrl: `${API_URL}/cubejs-api/v1`,
}
);
You can optionally store this token in local storage or in a cookie, so that you can then use it to query the Cube API.
Using JSON Web Key Sets
Looking for a guide on how to connect a specific identity provider? Check out our recipes for using Auth0 or AWS Cognito with Cube.
As mentioned previously, Cube supports verifying JWTs using industry-standard JWKS. The JWKS can be provided either from a URL, or as a JSON object conforming to JWK specification RFC 7517 Section 4 (opens in a new tab), encoded as a string.
Using a key as a JSON string
Add the following to your cube.js
configuration file:
module.exports = {
jwt: {
key: "<JWK_AS_STRING>",
},
};
Or configure the same using environment variables:
CUBEJS_JWT_KEY='<JWK_AS_STRING>'
Using a key from a URL
When using a URL to fetch the JWKS, Cube will automatically cache the response, re-use it and update if a key rotation has occurred.
Add the following to your cube.js
configuration file:
module.exports = {
jwt: {
jwkUrl: "<URL_TO_JWKS_JSON>",
},
};
Or configure the same using environment variables:
CUBEJS_JWK_URL='<URL_TO_JWKS_JSON>'
Verifying claims
Cube can also verify the audience, subject and issuer claims in JWTs. Similarly
to JWK configuration, these can also be configured in the cube.js
configuration file:
module.exports = {
jwt: {
audience: "<AUDIENCE_FROM_IDENTITY_PROVIDER>",
issuer: ["<ISSUER_FROM_IDENTITY_PROVIDER>"],
subject: "<SUBJECT_FROM_IDENTITY_PROVIDER>",
},
};
Using environment variables:
CUBEJS_JWT_AUDIENCE='<AUDIENCE_FROM_IDENTITY_PROVIDER>'
CUBEJS_JWT_ISSUER='<ISSUER_FROM_IDENTITY_PROVIDER>'
CUBEJS_JWT_SUBJECT='<SUBJECT_FROM_IDENTITY_PROVIDER>'
Custom claims namespace
Cube can also extract claims defined in custom namespaces. Simply specify the
namespace in your cube.js
configuration file:
module.exports = {
jwt: {
claimsNamespace: "my-custom-namespace",
},
};
Authentication integration
When using Cube Cloud, you can enrich the security context with information about an authenticated user, obtained during their authentication or loaded via an LDAP integration.
Authentication integration is available in Cube Cloud on all product tiers (opens in a new tab).
You can enable the authentication integration by navigating to the Settings → Configuration of your Cube Cloud deployment and using the Enable Cloud Auth Integration toggle.