I'm attempting to integrate a Superset dashboard into our angular application(V16). Unfortunately, when embedding the dashboard, it consistently returns a "403: Forbidden" error, even when using an admin account.

Superset Application Config

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

CORS_OPTIONS = {
    "supports_credentials": True,
    "origins": ["http://localhost:4200"],    
    "allow_headers": ["*"],
    "resources":["*"],
},

PUBLIC_ROLE_LIKE_GAMMA = True
SESSION_COOKIE_SAMESITE = None
ENABLE_PROXY_FIX = True
GUEST_ROLE_NAME = "Gamma"`

Frontend Application

``` embedDashboard({ id: '', // given by the Superset embedding UI supersetDomain: '', mountPoint: document.getElementById('my-superset-container'), // html element in which iframe render fetchGuestToken: () => this.fetchSupersetData(),

  debug: true,
});`

async fetchSupersetData() { try { const apiUrl = 'http://localhost:8081/users/me/superset-token';

  const response = await fetch(apiUrl, {
    method: 'GET'
  });

  if (!response.ok) {
    throw new Error(`HTTP error! Status: ${response.status}`);
  }

  const data = await response.text();
  return data;
} catch (error) {
  console.error('Error fetching Superset data:', error);
  throw error;
}

}

The frontend simply calls the /superset-token from backend and passes it to the embedDashboard

### Backend Application

public String loginAndGetAccessToken() { var restTemplate = solutionsFactory.createNewRestTemplate();

    String supersetUrl = "https://bi.cargoai.co/api/v1/security/login";
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

    var username = "";
    var password = "";


    String requestBody = "{\"username\": \"" + username + "\", \"password\": \"" + password + "\", \"provider\": \"db\", \"refresh\": true}";
    HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);

    ResponseEntity<Superset> response = restTemplate.postForEntity(supersetUrl, entity, Superset.class);

    if (response.getStatusCode().is2xxSuccessful()) {
        return response.getBody().getAccessToken();
    } else {
        throw new RuntimeException("Authentication failed");
    }
}

public CsrfTokenAndCookie getCsrfToken(String accessToken) {
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "Bearer " + accessToken);
    ResponseEntity<CsrfToken> response = restTemplate.exchange(SUPRESET_BASE + "/api/v1/security/csrf_token/", HttpMethod.GET, new HttpEntity<>(headers), CsrfToken.class);
    return new CsrfTokenAndCookie(response.getBody().getResult(), response.getHeaders().getFirst("Set-Cookie"));
}

public String createGuestToken(String accessToken, String csrfToken, String cookies) {
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "Bearer " + accessToken);
    headers.setContentType(MediaType.APPLICATION_JSON);
    headers.set("Referer", SUPRESET_BASE + "/api/v1/security/csrf_token/");
    headers.set("X-CSRFToken", csrfToken);
    headers.set("Cookie", cookies);

    String guestTokenEndpoint = SUPRESET_BASE + "/api/v1/security/guest_token/";

    String dashboardId = "";

    String requestBody = "{\"user\":{\"username\":\\",\"first_name\":\"\",\"last_name\":\"\"},\"resources\":[{\"type\":\"dashboard\",\"id\":\"" + dashboardId + "\"}],\"rls\":[]}";

    HttpEntity<String> request = new HttpEntity<>(requestBody, headers);
    ResponseEntity<GuestToken> response = restTemplate.exchange(guestTokenEndpoint, HttpMethod.POST, request, GuestToken.class);

    return response.getBody().getToken();
}

it has 3 methods:

- loginAndGetAccessToken - Login user the admin creds and get access token
- getCsrfToken - To get csrf token
- createGuestToken - To get guest token(we also tried with admin account on the place of guest account)


**Controller**

    @GetMapping("me/superset-token")
public ResponseEntity<String> getGuestToken() {
        String accessToken = userService.loginAndGetAccessToken();
        CsrfTokenAndCookie csrfToken = userService.getCsrfToken(accessToken);
        String guestToken = userService.createGuestToken(accessToken, csrfToken.getCsrfToken(), csrfToken.getCookies());
        return ResponseEntity.ok(guestToken);
    }

### 403 Error
I'm able to fetch the guest token but 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'm expecting to see actual superset dashboard on my angular application

### Actual results
403 error when fetching this API `GET /embedded/<dashboard-id>`

`{"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."}]}}]}` 

#### Screenshots

403 Error
![image](https://github.com/apache/superset/assets/35264391/dc4a4136-6e8d-4537-a1d7-8bbdcedff402)

Request  & Response Headers
![image](https://github.com/apache/superset/assets/35264391/fd0932c9-e29c-40cf-82c3-ae485e53434e)


### Environment

(please complete the following information):

- browser type and version: Chrome
- superset version: ^0.1.0-alpha.10
- Java version: V17
- Superset version: 3.0.1 (latest)
- node.js version: V18
- any feature flags active: {
    "ALERT_REPORTS": True,
    "THUMBNAILS": True,
    "THUMBNAILS_SQLA_LISTENERS": True,
    'PRESTO_EXPAND_DATA': True,
    "DASHBOARD_RBAC": True,
    "LISTVIEWS_DEFAULT_CARD_VIEW": True,
    "HORIZONTAL_FILTER_BAR": True,
    "TAGGING_SYSTEM": True,
    "EMBEDDED_SUPERSET": True,
}

### Checklist

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

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

### Additional information

We found this similar issue https://github.com/apache/superset/issues/22258 but the solution given didn't help. not sure what we are missing here.





**Comment From: pongsathorn-ph**

@MickJerin12  Please follow this config maybe resolve your problem.

**Maybe you forget config about TALISMAN**

**superset_config.py**
```python
ALLOW_ORIGINS = ['YOUR_BACKEND_URL','http://localhost:4200']

# Cross Origin Config
ENABLE_CORS = True
CORS_OPTIONS = {
    'supports_credentials': True,
    'allow_headers': ['*'],
    'resources':['*'],
    'origins': ALLOW_ORIGINS
}

# CSRF Config
WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = 300 # A CSRF token that expires in 5 minutes

# Talisman Config
TALISMAN_ENABLED = True
TALISMAN_CONFIG = {
    "content_security_policy": {
        "frame-ancestors": ALLOW_ORIGINS
    },
    "force_https": False,
    "force_https_permanent": False,
    "frame_options": "ALLOWFROM",
    "frame_options_allow_from": "*"
}

# Dashboard embedding
GUEST_ROLE_NAME = "YOUR_GUEST_ROLE_NAME"
GUEST_TOKEN_JWT_SECRET = "CUSTOM_GUEST_TOKEN_JWT_SECRET"
GUEST_TOKEN_JWT_EXP_SECONDS = 300  # 5 minutes

app.component.html

<div id="my-superset-container" style="height: 100vh;"></div>

app.component.ts

async ngOnInit(): Promise<void> {
    const myDashboard = embedDashboard({
            id: 'YOUR_DASHBOARD_EMBED_ID',
            supersetDomain: 'YOUR_SUPERSET_DOMAIN',
            mountPoint: document.getElementById('my-superset-container') as HTMLElement, // any html element that can contain an iframe
            fetchGuestToken: async () => await this.supersetService.getGuestToken(),
            dashboardUiConfig: {
                // dashboard UI config: hideTitle, hideTab, hideChartControls, filters.visible, filters.expanded (optional)
                hideTitle: false,
                filters: {
                    expanded: false,
                },
            },
        });

    myDashboard.then((data) => {
      const iframe = document.querySelector('iframe') as HTMLIFrameElement;
      if (iframe !== null) {
        iframe.style.width = '100%';
        iframe.style.height = '100%';
        iframe.style.border = 'none';
      }
    });
  }

Comment From: Lau08

This config worked for me:

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

GUEST_ROLE_NAME = "Gamma"
GUEST_TOKEN_JWT_SECRET = "your-secret-here"
GUEST_TOKEN_JWT_AUDIENCE = "audi"

TALISMAN_ENABLED = False

OVERRIDE_HTTP_HEADERS = {
    "X-Frame-Options": "ALLOWALL",
    "Content-Security-Policy": "frame-ancestors 'self' http://localhost:5173"
}
ENABLE_CORS = True

And in the dashboard to embed in superset, copy the URL like this: http://localhost:5173 with the http://

Image

This worked using a guest token, payload to get it from the Svelte application in my case, and using the SDK:

const payload = {
        user: {
            first_name: 'Embedded first_name',
            last_name: 'Embedded last_name',
            username: 'Embedded_user'
        },
        resources: [
            {
                id: SUPERSET_DASHBOARD_ID, //your dashboard id
                type: 'dashboard'
            }
        ],
        rls_rules: [],
        aud: "audi", // same as GUEST_TOKEN_JWT_AUDIENCE in superset
        type: 'guest'
    };

const token = encodeJwt(payload, SUPERSET_GUEST_SECRET);