# JSON Web Token authentication

Some visualization tools (e.g., custom front-end applications) can pass access tokens based
on the [JSON Web Token][wiki-jwt] (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:

<div style={{ textAlign: "center" }}>
  <img
    src="https://ucarecdn.com/98431f1f-4693-4218-adcc-34e8635eb2dd/"
    style={{ border: "none" }}
    width="80%"
  />
</div>

## Configuration

Relevant configuration options: [`check_auth`][ref-config-check-auth] and [`jwt`][ref-config-jwt].

Relevant environment variables: <EnvVar>CUBEJS_API_SECRET</EnvVar>, <EnvVar>CUBEJS_JWT_KEY</EnvVar>, <EnvVar>CUBEJS_JWK_URL</EnvVar>,
<EnvVar>CUBEJS_JWT_AUDIENCE</EnvVar>, <EnvVar>CUBEJS_JWT_ISSUER</EnvVar>, <EnvVar>CUBEJS_JWT_SUBJECT</EnvVar>, <EnvVar>CUBEJS_JWT_CLAIMS_NAMESPACE</EnvVar>.

## Custom authentication

Cube allows you to provide your own JWT verification logic. You can use the
[`check_auth`][ref-config-check-auth] configuration option to verify a JWT and set the security context.

A typical use case would be:

1.  A web server serves a page which needs to communicate with the Cube API.
2.  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.
3.  The token is used for calls to the Cube API.
4.  The token is received by Cube, and verified using any available JWKS (if configured)
5.  Once decoded, the token claims are injected into the [security
    context][ref-sec-ctx].

<InfoBox>

**In development mode, the token is not required for authorization**, but you
can still use it to [pass a security context][ref-sec-ctx].

</InfoBox>

## 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 <EnvVar>CUBEJS_API_SECRET</EnvVar>.

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.

<InfoBox>

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][link-jwt-docs].

</InfoBox>

You can find a library to generate JWTs for your programming language
[here][link-jwt-libs].

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.

```javascript
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:

```javascript
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:

```javascript
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

<InfoBox>

Looking for a guide on how to connect a specific identity provider? Check out
our recipes for using [Auth0][ref-recipe-auth0] or [AWS
Cognito][ref-recipe-cognito] with Cube.

</InfoBox>

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][link-jwk-ref], encoded as a string.

### Using a key as a JSON string

Add the following to your `cube.js` configuration file:

```javascript
module.exports = {
  jwt: {
    key: "<JWK_AS_STRING>"
  }
}
```

Or configure the same using environment variables:

```dotenv
CUBEJS_JWT_KEY='<JWK_AS_STRING>'
```

### Using a key from a URL

<InfoBox>

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.

</InfoBox>

Add the following to your `cube.js` configuration file:

```javascript
module.exports = {
  jwt: {
    jwkUrl: "<URL_TO_JWKS_JSON>"
  }
}
```

Or configure the same using environment variables:

```dotenv
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:

```javascript
module.exports = {
  jwt: {
    audience: "<AUDIENCE_FROM_IDENTITY_PROVIDER>",
    issuer: ["<ISSUER_FROM_IDENTITY_PROVIDER>"],
    subject: "<SUBJECT_FROM_IDENTITY_PROVIDER>"
  }
}
```

Using environment variables:

```dotenv
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:

```javascript
module.exports = {
  jwt: {
    claimsNamespace: "my-custom-namespace"
  }
}
```


[wiki-jwt]: https://en.wikipedia.org/wiki/JSON_Web_Token
[link-jwt-docs]: https://github.com/auth0/node-jsonwebtoken#token-expiration-exp-claim
[link-jwt-libs]: https://jwt.io/#libraries-io
[link-jwk-ref]: https://tools.ietf.org/html/rfc7517#section-4
[ref-config-check-auth]: /product/configuration/reference/config#check_auth
[ref-config-jwt]: /product/configuration/reference/config#jwt
[ref-recipe-auth0]: /product/auth/recipes/auth0-guide
[ref-recipe-cognito]: /product/auth/recipes/aws-cognito
[ref-sec-ctx]: /product/auth/context