question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

403 Forbidden error when trying to embed a dashboard & view it using a guest user token

See original GitHub issue

I am trying to embed a superset dashboard into a simple front-end application. However, when the embedded dashboard always throws 403: Forbidden. I am pretty sure I have set the correct permissions and everything. I even tried accessing it using admin user, still it fails.

How to reproduce the bug

The source for the application can be found here - https://github.com/adimyth/superset_embedded

superset application

Added the following configuration in superset_config.py

FEATURE_FLAGS = {"ALERT_REPORTS": True, "EMBEDDED_SUPERSET": True}

SESSION_COOKIE_SAMESITE = None
ENABLE_PROXY_FIX = True
PUBLIC_ROLE_LIKE_GAMMA = True
CORS_OPTIONS = {
    'supports_credentials': True,
    'allow_headers': ['*'],
    'resources': ['*'],
    'origins': ['http://localhost:8088', 'http://localhost:8000']
}

This gave me the following dashboard it to embed into my application Screenshot 2022-11-29 at 2 28 54 PM

frontend application

<head>
    <script src="https://unpkg.com/@preset-sdk/embedded"></script>
    <style>
        iframe {
            height: 100%;
            width: 100%;
            border: none;
        }
    </style>
</head>
<body>
    <p id="dashboard-container"> </p>
    <script>
        // 1. Request guest_token from our backend, which runs at localhost:8000 by default 
            async function fetchGuestTokenFromBackend() {
                let response = await fetch('http://127.0.0.1:8000/guest-token');
                let data = await response.json()
                return data
        }

        // 2. Uses Preset Embedded SDK to embed the dashboard as iFrame
        const myDashboard = presetSdk.embedDashboard({
          id: "{{ DASHBOARD_ID }}",
          supersetDomain: "{{ SUPERSET_DOMAIN }}",
          mountPoint: document.getElementById("dashboard-container"),
          fetchGuestToken: () => fetchGuestTokenFromBackend(),
          dashboardUiConfig: { hideTitle: true, hideChartControls: true}
        });
    </script>
</body>

The frontend simply calls the /guest-token from backend and passes it to the presetSdk.embedDashboard

backend application

The /guest-token endpoint simply calls 2 methods from the helper (superset.py) file

@app.get("/guest-token")
async def analytics_view(request: Request):
    access_token = superset.authenticate()
    guest_token = superset.get_guest_token_for_dashboard(
        dashboard_id=DASHBOARD_ID, access_token=access_token
    )
    return guest_token

The helper has 2 methods - authenticate() which authenticates the superset-admin user & get_guest_token_for_dashboard which is used to generate access token for the guest user

import json
import os

import requests
from dotenv import load_dotenv

load_dotenv()


URL_AUTH = os.getenv("URL_AUTH")
URL_GUEST_TOKEN = os.getenv("URL_GUEST_TOKEN")
USERNAME = os.getenv("USERNAME")
FIRST_NAMER = os.getenv("FIRST_NAMER")
LAST_NAME = os.getenv("LAST_NAME")


def authenticate(
    username="admin",
    password="admin",
):
    response = requests.post(
        "http://localhost:8088/api/v1/security/login",
        headers={
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Access-Control-Allow-Origin": "http://localhost:8000",
        },
        data=json.dumps(
            {
                "username": username,
                "password": password,
                "provider": "db"
            }
        ),
    )
    return response.json()["access_token"]


def get_guest_token_for_dashboard(
    dashboard_id,
    access_token,
    username=USERNAME,
    first_name=FIRST_NAMER,
    last_name=LAST_NAME,
):
    response = requests.post(
        URL_GUEST_TOKEN,
        data=json.dumps(
            {
                "user": {
                    "username": username,
                    "first_name": first_name,
                    "last_name": last_name,
                },
                "resources": [
                    {
                        "type": "dashboard",
                        "id": dashboard_id,
                    }
                ],
                "rls": [],
            }
        ),
        headers={
            "Authorization": "Bearer " + access_token,
            "Accept": "application/json",
            "Content-Type": "application/json",
        },
    )
    return response.json()["token"]

Finally we pass environment variables. Note that the DASHBOARD_ID matches from the screenshot above. Also note that I am passing superset-admin creds to the embedded dashboard

URL_AUTH=http://localhost:8088/api/v1/security/login
URL_GUEST_TOKEN=http://localhost:8088/api/v1/security/guest_token/
USERNAME=admin
FIRST_NAMER=Supserset
LAST_NAME=Admin
DASHBOARD_ID=b0a944b2-4ab5-47b7-a31d-c3eca4c36397
SUPERSET_DOMAIN=http://localhost:8088/

Error

When loading the frontend application which has the embedded dashboard, it returns -

{"errors": [{"message": "403 Forbidden: You don't have the permission to access the requested resource. It is either read-protected or not readable by the server.", "error_type": "GENERIC_BACKEND_ERROR", "level": "error", "extra": {"issue_codes": [{"code": 1011, "message": "Issue 1011 - Superset encountered an unexpected error."}]}}]}

Expected results

I was expecting to see the actual dashboard in the frontend application

Actual results

Screenshot 2022-11-29 at 2 37 17 PM

What’s surprising is that after decoding the guest token, we can clearly see that the user is superset admin & has access to the dashboard 🤯 Screenshot 2022-11-29 at 2 39 15 PM

Environment

(please complete the following information):

  • browser type and version: Chrome
  • superset version: Built from the latest code as of 29th Nov
  • python version: 3.9
  • node.js version: NA
  • any feature flags active: {"ALERT_REPORTS": True, "EMBEDDED_SUPERSET": True}

Checklist

Make sure to follow these steps before submitting your issue - thank you!

  • I have checked the superset logs for python stacktraces and included it here as text if there are any.
  • I have reproduced the issue with at least the latest released version of superset.
  • I have checked the issue tracker for the same issue and I haven’t found one similar.

Issue Analytics

  • State:closed
  • Created 10 months ago
  • Reactions:2
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
adimythcommented, Dec 1, 2022

The first thing to try would be to remove ALL the allowed domains and leave the field empty.

Background: The allowed domains field is incorrectly labeled in the UI. What this field does is to check the “Referer” header and compare it against the values in this field, which is IMO a bit awkward.

Relevant discussion in Slack. https://apache-superset.slack.com/archives/C01EP56QGTS/p1663143592850569?thread_ts=1663071066.037159&cid=C01EP56QGTS

If that doesn’t help, the next step is to investigate the Guest permissions configuration.

Adding the following in superset_config.py seems to be working for me -

# Dashboard embedding
GUEST_ROLE_NAME = "Gamma"
GUEST_TOKEN_JWT_SECRET = "test-guest-secret-change-me"
GUEST_TOKEN_JWT_ALGO = "HS256"
GUEST_TOKEN_HEADER_NAME = "X-GuestToken"
GUEST_TOKEN_JWT_EXP_SECONDS = 300  # 5 minutes

I shall test this out & revert!

1reaction
cwegenercommented, Nov 30, 2022

The first thing to try would be to remove ALL the allowed domains and leave the field empty.

Background: The allowed domains field is incorrectly labeled in the UI. What this field does is to check the “Referer” header and compare it against the values in this field, which is IMO a bit awkward.

Relevant discussion in Slack. https://apache-superset.slack.com/archives/C01EP56QGTS/p1663143592850569?thread_ts=1663071066.037159&cid=C01EP56QGTS

If that doesn’t help, the next step is to investigate the Guest permissions configuration.

Read more comments on GitHub >

github_iconTop Results From Across the Web

What am I missing while trying to embed a dashboard? #18814
The correct dashboard gets identified and still throws 403 errors. I even added all users to the access list in Superset UI.
Read more >
How to Fix a 403 Forbidden Error on Your WordPress Site
The 403 Forbidden error means that your server is working, but you no longer have permission to view all or some of your...
Read more >
Error 403 Forbidden in OneDrive or SharePoint - Microsoft Learn
Error 403 can occur if the user is trying to access a OneDrive site that is not provisioned. Have the user try to...
Read more >
Power BI API returning 403 forbidden when fetching ...
To use an Embed Token, you should call the Embed URL with it. ... You need to provide the workspaceId where the dashboard...
Read more >
HTTP Error 403 Forbidden: What It Means and How to Fix It
The 403 (Forbidden) status code indicates that the server understood the request ... Authenticate yourself with a more appropriate account.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found