# Dashboard Embedding

To unlock the full potential of your data and analytic dashboards you will want to share them securely with your users.
This is where embedding comes in. You can embed any dashboard in your application using the JavaScript Embedding API. No Iframes needed.

Here is an example:

<ShaperDashboard id="vmw80z157nz7200teo9l35yi" />

**IFrames:** If you need to use an IFrame or have other requirements for embedding, please reach out [on Github](https:/github.com/taleshape-com/shaper/issues).

If you are looking to share dashboards publicly, you can do so by creating a public link instead:
[Share Dashboards Publicly](https://taleshape.com/shaper/docs/public-sharing)

The general embedding workflow is as follows:
1. Get an API key
2. Generate a JWT token in your backend to give a user access to the specific dashboard
3. Use the JWT token to authenticate the user in your frontend

You can use the Embedding JS API directly or use the [shaper-react](https://github.com/taleshape-com/shaper-react) library to embed Shaper into a React application.
**Other Frameworks:** If you would like to see deeper integration into other frameworks, please reach out [on Github](https:/github.com/taleshape-com/shaper/issues).

## Example Applications

The fastest way to understand how to embed Shaper is to look at a complete example application:
[Node.js Backend + JS API](https://github.com/taleshape-com/shaper-embedding-example)
    [React-Router + shaper-react](https://github.com/taleshape-com/shaper-react-example)
## Step by Step

1. Create an API key
1. In Shaper, click on "Admin" in the bottom-left.
2. Then click on "API Keys" and then on "New".
3. Give the key a name, select the permission "Generate JWT" and click "Create Key".
4. Copy the key and save it somewhere safe before closing the dialog.
2. Get a dashboard ID
1. Open the dashboard you want to embed.
2. Copy the ID from the sidebar on the left.
3. Include Shaper in your application:
   ```html
        <script src="http://localhost:5454/embed/shaper.js"></script>
        ```
    ```bash
        npm install shaper-react
        ```
4. Embed a dashboard into your frontend:
   ```html
        <div id="dashboard-container"></div>
        <script>
          const dashboard = shaper.dashboard({
            container: document.getElementById("dashboard-container"),
            dashboardId: "<your-dashboard-id>",
            async getJwt() {
              // Call your backend, then return a valid JWT
            },
          });
        </script>
        ```
    ```tsx
        import { ShaperDashboard } from "shaper-react";
        // ...
        <ShaperDashboard
          baseUrl={"http://localhost:5454"}
          id={"<your-dashboard-id>"}
          jwt={jwt}
          refreshJwt={() => {
            // Call your backend, then set the `jwt` variable to a valid JWT
          }}
        />
        ```
5. Call the Shaper API from your **backend** to generate a JWT.
   Endpoint:
    ```
    POST http://localhost:5454/api/auth/token
    ```

    Request:
    ```json
    {
        "token": "<your-api-key>",
        "dashboardId": "<your-dashboard-id>"
    }
    ```
    Response:
    ```json
    {
        "jwt": "<generated-jwt>"
    }
    ```
    ```javascript
        const { jwt } = await fetch(`http://localhost:5454/api/auth/token`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            token: "<your-api-key>",
            dashboardId: "<your-dashboard-id>",
          }),
        })
        ```
    By default, the JWT is valid for 10 minutes. Make sure your application logic allows for generating a new JWT when the old one expires.

    Make sure to authenticate the user in your backend before generating the JWT and only allow access to the dashboard if the user is allowed to see it.

**Keep your API key safe:** Never show the API key to a user.
    Never send your API key to the frontend.

    Always generate the JWT token in your backend and send it to the frontend.

    And also don't let the frontend pass the shaper base url to the backend.
    Otherwise a malicious user could tell your backend to send the auth request to another endpoint and get access to your API key.
## JWT Variables

**Optional:** Use variables to customize the dashboard to the user's context and restrict what they are able to see.

You can pass an optional `variables` property to `/api/auth/token` to bind the generated JWT to specific variables.

Pass an object where each key is the name of the variable and the values are either strings or array of strings.

For example, your request could look like this:
```json
{
    "token": "<your-api-key>",
    "dashboardId": "<your-dashboard-id>",
    "variables": {
        "user_id": "123",
        "project_id": ["456", "789"]
    }
}
```

In SQL you can then use the variables like this:
```sql
SELECT count() FROM events WHERE user_id = getvariable('user_id');
SELECT * FROM projects WHERE project_id IN getvariable('project_id');
```

**JWT variables override dashboard variables:** Variables defined on the dashboard itself [through dropdowns or other filters](https://taleshape.com/shaper/docs/getting-started/#defining-variables)
are overridden by JWT variables if they are using the same name.

You might have noticed the "Variables" section in sidebar of the dashboard editor.
You can use this to emulate setting a variables to test out dashboards before actually embedding them.

## Generate JWT in Your Application

Instead of calling Shaper's API to get a JWT, you can also directly generate a JWT in the embedding application by using a shared JWT secret.

This is allows you to avoid the extra API call to Shaper, but it means you are responsible for defining a JWT secret and generating correct JWT tokens.

### How to Generate a JWT

1. Generate a secure JWT secret
2. Set the environment variable `SHAPER_JWT_SECRET` to pass the JWT secret to Shaper
3. In your backend logic that generates the JWT for Shaper's `getJwt` callback use a JWT library to generate a token.
   - Ensure that `dashboardId` is always set so the user is restricted a specific dashboard
    - Optionally set `variables`
    - You can also set `userId`, `userName` and `userEmail` to log them as extra context in Shaper.

Here is a JavaScript example:
```js
import jwt from "jsonwebtoken";

const token = jwt.sign(
  {
    // Required: dashboardId scopes the token to a specific dashboard
    dashboardId: input.dashboardId,
    // OptionalUser identity
    userId: input.userId,
    userName: input.userName,
    // Optional: Variables accessible in the dashboard
    variables: {
      project_id: input.projectId,
      organization_id: input.organizationId,
    },
  },
  secret: process.env.SHAPER_JWT_SECRET,
  {
    expiresIn: "1h",
  },
);
```