Find everything you need to get certified on Fabric—skills challenges, live sessions, exam prep, role guidance, and more. Get started
I have an app registration that I'm using in my application to access the Microsoft Calendar.
I want to embed a report into my app but I want to avoid the user to login everytime to view the redered report. I added the required permissions (Report.Read.All, Workspace.Read.All, Dashboard.Read.All) to my app registration on the Azure Portal.
To test the permission I tried to render the embedded iframe with the src param compiled and it worked correctly but I had to login every time I opened the html file, so I tried to retrieve the access token from the Microsoft login API (https://login.microsoftonline.com/common/oauth2/v2.0/token) but I had that the origin is not correct and should must be a Single Page Application. Despite I added the http://localhost URI on the Azure Application SPA panel, this error came anyway.
I hard coded the access token statically and I tried to retrieve the report from the Reports API (https://api.powerbi.com/v1.0/myorg/reports/{reportId}) but this time I got a 403 reponse with no body, both on the fetch call on the html and on postman.
Is there anything I'm missing or is there a better way to do this? Thanks.
<script src="https://cdnjs.cloudflare.com/ajax/libs/powerbi-client/2.23.1/powerbi.min.js"></script>
// Login data.
const refreshToken = "REFRESH_TOKEN";
const clientId = "CLIENT_ID";
const tenantId = "TENANT_ID";
const scope = ".default";
const grantType = "refresh_token";
const clientSecret = "CLIENT_SECRET";
// Report data.
const reportId = "REPORT_ID";
const accessToken = "ACCESS_TOKEN"
async function getAccessToken() {
// const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
// const response = await fetch(url, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/x-www-form-urlencoded'
// },
// body: new URLSearchParams({
// 'grant_type': 'client_credentials',
// 'client_id': clientId,
// 'client_secret': clientSecret,
// 'scope': 'https://graph.microsoft.com/.default'
// })
// });
// const data = await response.json();
// console.log(data);
// return data.access_token;
return accessToken;
}
async function getEmbedDetails() {
const url = `https://api.powerbi.com/v1.0/myorg/reports/${reportId}`;
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const data = await response.json();
return data;
}
(async () => {
try {
const accessToken = await getAccessToken();
const embedDetails = await getEmbedDetails();
const embedUrl = embedDetails.embedUrl;
const models = window['powerbi-client'].models;
const embedConfig = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: reportId,
permissions: models.Permissions.All,
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: true
}
};
const reportContainer = document.getElementById('reportContainer');
powerbi.embed(reportContainer, embedConfig);
} catch (error) {
console.error('Error embedding Power BI report:', error);
}
})();
Solved! Go to Solution.
Hi, @francescod9
403 Forbidden error:
You should ensure that your application is registered with the correct API permissions and has administrator consent. Double-check the Client ID, Client Secret, and Tenant ID. access tokens have a limited validity period. If a session lasts longer than the token's expiration date, ensure that the token is refreshed periodically.
Ensure that your application registration is properly configured to allow CORS from the application domain.
In Application Registration, go to API Permissions and add the permissions required by Power BI (e.g., , , Report.Read.All).Workspace.Read.AllDashboard.Read.All grants the administrator consent for these permissions.
To obtain an access token using the client credential stream, you can use the following code:
async function getAccessToken() {
const tenantId = "YOUR_TENANT_ID";
const clientId = "YOUR_CLIENT_ID";
const clientSecret = "YOUR_CLIENT_SECRET";
const scope = "https://analysis.windows.net/powerbi/api/.default";
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'grant_type': 'client_credentials',
'client_id': clientId,
'client_secret': clientSecret,
'scope': scope
})
});
const data = await response.json();
if (response.ok) {
return data.access_token;
} else {
throw new Error(data.error_description);
}
}
Using the acquired access token, you can embed the report into your application:
<script src="https://cdnjs.cloudflare.com/ajax/libs/powerbi-client/2.23.1/powerbi.min.js"></script>
<div id="reportContainer" style="height: 600px;"></div>
<script>
const reportId = "YOUR_REPORT_ID";
const accessToken = await getAccessToken(); // Call the function to get the access token
async function getEmbedDetails() {
const url = `https://api.powerbi.com/v1.0/myorg/reports/${reportId}`;
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const data = await response.json();
return data;
}
(async () => {
try {
const embedDetails = await getEmbedDetails();
const embedUrl = embedDetails.embedUrl;
const models = window['powerbi-client'].models;
const embedConfig = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: reportId,
permissions: models.Permissions.All,
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: true
}
};
const reportContainer = document.getElementById('reportContainer');
powerbi.embed(reportContainer, embedConfig);
} catch (error) {
console.error('Error embedding Power BI report:', error);
}
})();
</script>
hackcrr
If this post helps, then please consider Accept it as the solution and kudos to this post to help the other members find it more quickly
We tried.
CORS error was thrown by the Live Server. We tried to do the same calls from a NodeJS Server and we got the access token.
The problem now is that the getEmbedDetails call returns a 401 Status respost both from NodeJS and postman.
THe following code is the actual NodeJS code that we are using:
async function getAccessToken() {
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
const response = await axios.post(url, {
'grant_type': 'client_credentials',
'client_id': clientId,
'client_secret': clientSecret,
'scope': "https://analysis.windows.net/powerbi/api/.default"
},
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
return response.data.access_token;
}
async function getEmbedDetails() {
let accessToken = await getAccessToken();
const url = `https://api.powerbi.com/v1.0/myorg/reports/${reportId}`;
const response = await axios.get(url, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
}).catch((error) => {
console.log(error)});
return response.data;
}
getEmbedDetails().then((data) => {
console.log(data);
});
Are we missing any step?
Hi, @francescod9
403 Forbidden error:
You should ensure that your application is registered with the correct API permissions and has administrator consent. Double-check the Client ID, Client Secret, and Tenant ID. access tokens have a limited validity period. If a session lasts longer than the token's expiration date, ensure that the token is refreshed periodically.
Ensure that your application registration is properly configured to allow CORS from the application domain.
In Application Registration, go to API Permissions and add the permissions required by Power BI (e.g., , , Report.Read.All).Workspace.Read.AllDashboard.Read.All grants the administrator consent for these permissions.
To obtain an access token using the client credential stream, you can use the following code:
async function getAccessToken() {
const tenantId = "YOUR_TENANT_ID";
const clientId = "YOUR_CLIENT_ID";
const clientSecret = "YOUR_CLIENT_SECRET";
const scope = "https://analysis.windows.net/powerbi/api/.default";
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'grant_type': 'client_credentials',
'client_id': clientId,
'client_secret': clientSecret,
'scope': scope
})
});
const data = await response.json();
if (response.ok) {
return data.access_token;
} else {
throw new Error(data.error_description);
}
}
Using the acquired access token, you can embed the report into your application:
<script src="https://cdnjs.cloudflare.com/ajax/libs/powerbi-client/2.23.1/powerbi.min.js"></script>
<div id="reportContainer" style="height: 600px;"></div>
<script>
const reportId = "YOUR_REPORT_ID";
const accessToken = await getAccessToken(); // Call the function to get the access token
async function getEmbedDetails() {
const url = `https://api.powerbi.com/v1.0/myorg/reports/${reportId}`;
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const data = await response.json();
return data;
}
(async () => {
try {
const embedDetails = await getEmbedDetails();
const embedUrl = embedDetails.embedUrl;
const models = window['powerbi-client'].models;
const embedConfig = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: reportId,
permissions: models.Permissions.All,
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: true
}
};
const reportContainer = document.getElementById('reportContainer');
powerbi.embed(reportContainer, embedConfig);
} catch (error) {
console.error('Error embedding Power BI report:', error);
}
})();
</script>
hackcrr
If this post helps, then please consider Accept it as the solution and kudos to this post to help the other members find it more quickly
Check out the September 2024 Power BI update to learn about new features.
Learn from experts, get hands-on experience, and win awesome prizes.
User | Count |
---|---|
105 | |
46 | |
22 | |
21 | |
21 |