I am working with an ASP.NET Core 3.1 MVC application where I am attempting to implement Power BI in embedded view using the "App Owns Data" scenario and using a Service Principal.
I can successfully connect to the Power BI service using said Service Principal. I am able to retrieve tokens without issue and pass them through to the Power BI service where I can retrieve a list of reports and view individual reports without issue (using powerbi.embed()). However, when I call the powerbi.createReport() JavaScript method, it always returns "This content is not available" along with a 403 response when viewing in Fiddler.
Generating an access token
private async Task<string> GetPowerBIAccessToken()
{
string pBiClientId = powerBISettings.ApplicationId.ToString();
string pBiSecret = powerBISettings.ApplicationSecret.ToString();
var clientCredentials = new ClientCredential(pBiClientId, pBiSecret);
var authContext = new AuthenticationContext($"{powerBISettings.AuthorityUrl}/{powerBISettings.TenantId}", new TokenCache());
var token = await authContext.AcquireTokenAsync(powerBISettings.ResourceUrl, clientCredentials);
return token.AccessToken;
}
Code to generate a model to view a Power BI report
public async Task<EmbedConfig> ViewReport(Guid ReportId)
{
var result = new EmbedConfig { };
var accessToken = await GetPowerBIAccessToken();
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(powerBISettings.ApiUrl), tokenCredentials))
{
var workspaceId = powerBISettings.WorkspaceId.Value;
var reports = await client.Reports.GetReportsInGroupAsync(workspaceId);
var report = reports.Value.Where(a => a.Id == ReportId).FirstOrDefault();
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
var tokenResponse = await client.Reports.GenerateTokenAsync(workspaceId, report.Id, generateTokenRequestParameters);
result.EmbedToken = tokenResponse;
result.EmbedUrl = report.EmbedUrl;
result.Id = report.Id == null ? string.Empty : report.Id.ToString();
}
return result;
}
MVC view with embedded report to view above report - this works!
<style>
#reportContainer {
height: 600px;
width: 100%;
max-width: 2000px;
}
</style>
<script src="https://npmcdn.com/es6-promise@3.2.1"></script>
<script src="~/js/powerbi.min.js"></script>
<div id="reportContainer"></div>
@section scripts {
<script>
// Read embed application token from Model
var accessToken = "@Model.EmbedToken.Token";
// Read embed URL from Model
var embedUrl = "@Html.Raw(Model.EmbedUrl)";
// Read report Id from Model
var embedReportId = "@Model.Id";
// Get models. models contains enums that can be used.
var models = window['powerbi-client'].models;
// Embed configuration used to describe the what and how to embed.
// This object is used when calling powerbi.embed.
// This also includes settings and options such as filters.
// You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
var config = {
type: 'report',
tokenType: models.TokenType.Embed,
accessToken: accessToken,
embedUrl: embedUrl,
id: embedReportId,
permissions: models.Permissions.All,
settings: {
filterPaneEnabled: true,
navContentPaneEnabled: true
}
};
$(document).ready(function () {
// Get a reference to the embedded report HTML element
var reportContainer = $('#reportContainer')[0];
// Embed the report and display it within the div container.
powerbi.embed(reportContainer, config);
});
</script>
}
Code to generate the Model to create a new blank report
public async Task<EmbedConfig> CreateNewReport()
{
var result = new EmbedConfig { };
var accessToken = await GetPowerBIAccessToken();
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(powerBISettings.ApiUrl), tokenCredentials))
{
var workspaceId = powerBISettings.WorkspaceId.Value;
var generateTokenRequestParameters = new GenerateTokenRequest(TokenAccessLevel.Create, datasetId: "xyz", allowSaveAs: true);
var tokenResponse = await client.Reports.GenerateTokenForCreateInGroupAsync(workspaceId, generateTokenRequestParameters);
result.EmbedToken = tokenResponse;
result.DatasetId = "xyz";
}
return result;
}
MVC view to with embedded create report - doesn't work
<style>
#reportContainer {
height: 600px;
width: 100%;
max-width: 2000px;
}
</style>
<script src="https://npmcdn.com/es6-promise@3.2.1"></script>
<script src="~/js/powerbi.min.js"></script>
<div id="reportContainer"></div>
@section scripts {
<script>
// Read embed application token from Model
var accessToken = '@Model.EmbedToken.Token';
// Get models. models contains enums that can be used.
var models = window['powerbi-client'].models;
// Embed configuration used to describe the what and how to embed.
// This object is used when calling powerbi.embed.
// This also includes settings and options such as filters.
// You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
var config = {
accessToken: accessToken,
datasetId: '@Model.DatasetId',
embedUrl: 'https://embedded.powerbi.com/ReportEmbed'
};
$(document).ready(function () {
// Get a reference to the embedded report HTML element
var reportContainer = $('#reportContainer')[0];
// Embed the report and display it within the div container.
powerbi.createReport(reportContainer, config);
});
</script>
}
When the above view is loaded it returns this

Fiddler captures a 403 response

Does anybody know why this could be happening? The Service Principal has all API permissions assigned to the Power BI service (I followed the 'Create App' wizard within Power BI to create an App Registration in Azure AD). I just can't figure out why it keeps returning 403 - any help would be appreciated!