403 Forbidden error when trying to embed a dashboard & view it using a guest user token
See original GitHub issueI 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
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
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 🤯
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:
- Created 10 months ago
- Reactions:2
- Comments:6 (2 by maintainers)
Adding the following in
superset_config.py
seems to be working for me -I shall test this out & revert!
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.