---
url: https://docs.ridgedata.ai/guide/javascript-authentication.md
---
# JavaScript authentication

A JavaScript embed uses a short-lived JWT in the browser. Your server creates that JWT with a
Ridge API key after authenticating its own user.

## Create a dashboard token

Full request and response schemas for this endpoint are in the
[REST API reference](/reference/rest#tag/embed).

```http
POST https://app.ridgedata.ai/api/embed/token
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
```

```json
{
  "dashboardIds": ["dashboard-id-123"]
}
```

The response is `{ "token": "<jwt>", "expiresIn": 86400 }`, where `expiresIn` is the token's
lifetime in seconds. Return it from your own authenticated endpoint, then pass it to
`RidgeEmbed.load` in the browser.

::: warning Keep the API key on your server
An API key must never appear in browser code, page source, client logs, or a public build.
Your server is responsible for deciding which dashboard and rows the current user may see.
:::

Every token request must include `dashboardIds`, a non-empty list of the dashboards the token
may load. Each one must have JavaScript embedding turned on.

## Expiry and refresh

Embed JWTs expire after 24 hours and are not individually revocable. Create a token for each
page load and keep it specific to that user and session.

To keep a long-lived page signed in, pass `getToken` to `RidgeEmbed.load`, with the first
token's `expiresIn`. `getToken` returns a promise of a new `{ token, expiresIn }`. Your server
can pass Ridge's response body through unchanged:

```js
const getToken = async () => {
  const response = await fetch("/api/ridge-token", { credentials: "same-origin" });
  if (!response.ok) throw new Error("Could not refresh the Ridge token");
  return response.json(); // { token, expiresIn }
};

const first = await getToken();
const ridge = await RidgeEmbed.load({
  jwt: first.token,
  expiresIn: first.expiresIn,
  getToken,
  dashboardId: "dashboard-id-123",
  rootElementId: "ridge-dashboard"
});
```

The embed calls `getToken` at about 80% of the current token's lifetime, and again when a
request gets a 401. `expiresIn` is required: the embed counts it from when the token arrives,
so the viewer's clock does not affect it. Return a newly minted token each time. Failed calls
are retried with increasing delays until the current token expires. Then the embed reports an
error through `onError`. Your server checks the user on each call, so a user who has lost access stops
receiving tokens.

Without `getToken`, the embed uses `jwt` for its whole life. Fetch a new token and reload the
embed before it expires.

### Keep one session across refreshes

By default each token is its own session, so a refreshing page would split its activity,
including its data agent chat, across sessions. To keep them together, send the same
`sessionId` with every token request for that embed:

```json
{
  "dashboardIds": ["dashboard-id-123"],
  "sessionId": "user-session-id"
}
```

`sessionId` is 1 to 128 characters of letters, digits and `._~+/=-`. Create it on your server,
for example from your own login session, and never take it from the browser. Anyone who knows
it and holds a token with the same scope can rejoin that session, including its chat.

Ridge binds `sessionId` to the token's scope: the API key, the dashboard ids and the partition
filters. The same `sessionId` with a different scope starts a different session.

## Row-level access

Add `partitionFilters` when creating the JWT to enforce row-level access. Use partition
values from the authenticated server session. Validate any values supplied by the browser.

See [Partitioning](./partitioning) for examples and the distinction between partitions and
interactive filters.

## Requirements

* The API key needs the Embed Viewer role. Keys created for embedding get it by default.
* Embedding is a paid feature and is not available on the Free plan.

## Token request errors

Check the HTTP status before reading the response token:

| Status | What to check                                                                                                    |
| ------ | ---------------------------------------------------------------------------------------------------------------- |
| `400`  | Send a valid JSON object with a non-empty `dashboardIds` list.                                                   |
| `401`  | Check that the server sent a valid API key in `Authorization: Bearer <key>`.                                     |
| `403`  | Check the key's Embed Viewer role, its dashboard access, and that JavaScript embedding is on for each dashboard. |
| `404`  | Check that every dashboard id exists in the key's organization.                                                  |

Embedding also requires a paid plan. For machine-readable endpoint details, use the
[OpenAPI specification](/openapi.json).
