I am trying to embed a Power BI report in a Vue/Nuxt app without success. We are implementing against the App Owns Data model.
I can successfully retrieve an access token and generate an embed token for a specific report.
The tokens generated, and the report id I have, successfully resolve and embed the report via the Power BI Playground, so I know we have the correct details and permissions.
I am also using the official Power BI Client package from Microsoft to perform the embed:
https://www.npmjs.com/package/powerbi-client
When I try, I get the following:
I've confirmed that the Service Principal has admin rights to all workspaces, and the report I'm testing has been re-published to ensure it has the latest permissions, without success.
This is the code being implemented (with the data being passed via route currently):
<template>
<v-container
fluid
class="ma-0 pa-0"
>
<v-row class="app-bar ma-0 py-0 px-6">
<v-col
cols="12"
class="px-0"
>
<NuxtLink to="/"
><v-icon
color="#2670ca"
size="x-large"
>mdi-chevron-left
</v-icon>
</NuxtLink>
<div class="pl-3">{{ reportName }}</div>
</v-col>
</v-row>
</v-container>
<v-container
fluid
class="ma-0 pa-0 fill-height"
>
<div
id="report-container"
ref="reportContainer"
width="100%"
height="100%"
style="display: flex; flex-wrap: wrap; flex: 1 1 auto; max-width: 100%"
></div>
</v-container>
</template>
<script lang="ts" setup>
import { onMounted } from "vue";
import * as pbi from "powerbi-client";
const route = useRoute();
const user = useSupabaseUser();
console.log("Confirming login...");
watch(
user,
() => {
if (!user.value) {
return navigateTo("/login");
}
},
{ immediate: true }
);
const reportName = computed(() => (route.query.name === undefined ? "Unknown" : String(route.query.name)));
console.log("Available permissions...");
console.log(pbi.models);
onMounted(() => {
// Set up the configuration object that determines what to embed and how to embed it.
let embedConfiguration = {
// Incorrect: Using EntraID token
// accessToken: route.query.accessToken?.toString(),
// Correct: Using token from Generate Power Bi Token response
// Note: I've added state management since
accessToken: authStore.pbiToken,
embedUrl: route.query.embedUrl?.toString(),
id: route.query.id?.toString(),
permissions: pbi.models.Permissions.Read,
tokenType: pbi.models.TokenType.Embed,
type: route.query.reportType?.toString(),
pageView: "fitToWidth",
};
console.log("Check embed configuration...");
console.log({ embedConfiguration: embedConfiguration });
let powerbi = new pbi.service.Service(pbi.factories.hpmFactory, pbi.factories.wpmpFactory, pbi.factories.routerFactory);
// Get a reference to the HTML element that contains the embedded report.
let embedContainer = document.getElementById("report-container")!;
// Embed the report or dashboard.
let report = powerbi.embed(embedContainer, embedConfiguration);
report.off("loaded");
report.off("rendered");
report.on("error", function (err) {
console.log("Embed report error:");
console.log({ embedError: err });
report.off("error");
});
});
</script>
What could be missing/incorrect in our configuration/code that is not obvious from the MS docs?
EDIT
Something that does seem curious. I am making this call from New Zealand. When I request the access token at say 8:49 am on the 25 March (2024-03-25) the expiration date that comes back already seems invalid... i.e. timezone, etc.
Resolved: The time looks the same but 12 hrs out... however, being UTC it was not obvious that daylight savings was counted for, so the actual time was an hour earlier, meaning the 1 hour token expiry was valid.
EDIT 2
Have confirmed that my user has read permissions to the report I'm trying to view.
EDIT 3
I have tried against a Pro PBI License and still no luck.
The error message above: "403 Forbidden - Fail to initialise - Cannot resolve cluster" is described by MS as "Wrong token type or bad token". At this point I'm sure we are implementing via the App Owns Data method so the token type of "Embed" is correct.
How is one supposed to know if their token is 'bad'?, let alone what's wrong with it and how to fix it!
EDIT 4
The code I use to generate the access token is below, but I do not recall seeing anything about specifying a tokenType in the request body!?
export default defineEventHandler(async (event) => {
const runtimeConfig = useRuntimeConfig(event);
const params = {
client_id: String(runtimeConfig.pbClientId),
client_secret: String(runtimeConfig.pbClientSecret),
grant_type: "client_credentials",
scope: "https://analysis.windows.net/powerbi/api/.default",
authorityUrl: "https://login.microsoftonline.com/organizations/",
};
const requestParams = new URLSearchParams(params);
const getAccessTokenResponse = await $fetch(`https://login.microsoftonline.com/${runtimeConfig.pcTenantId}/oauth2/v2.0/token`, {
method: "POST",
mode: "no-cors",
body: requestParams,
});
console.log({ type: "API DEBUG", intent: "Get token to access Power BI resources", result: getAccessTokenResponse });
return {
data: getAccessTokenResponse,
};
});
From the Troubleshoot documentation, the reason for the error might be bad access Token or Embed Token type doesn't match the token type.
There is no information how you're generating the access Token in the question.
If you're generating the access Token by hitting endpoint https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
, Make sure you pass the scope for eg https://analysis.windows.net/powerbi/api/.default
.
In this scenario the Token type will be models.TokenType.Aad
and need to update it in your embedConfig.
If you're getting accessToken by hitting the Embedded Rest APIs Generate Token, then the Token type will be of models.TokenType.Embed
.
In order to generate the Embed Token, use the above token generated by you, Hit the Generate Token REST API by passing your previous token as a bearer token and you will get a new Token in the Response and it will be of type Embed
. Use that token to Embed the report.
If the issue still exists, need to provide more details on how you're generating the access Token.