Tutorial: Embed a Power BI report in an application for your organization
This tutorial explains how to embed a Power BI report in a .NET 5.0 application, as part of the embed for your organization (also known as user owns data) solution. In an embed for your organization solution, your app users need to authenticate against Power BI with their own credentials.
In this tutorial, you learn how to embed:
- A Power BI report
- In an embed for your organization app
- Using .NET 5.0
- With the
Microsoft.Identity.Web
library (this library is also supported in .NET Core)
Note
The full solution used in this tutorial, is available from the DOTNET5-UserOwnsData-Tutorial GitHub repository.
Prerequisites
A Power BI Pro or Premium Per User (PPU) license.
Note
The embed for your organization solution, is not supported on capacities based on A SKUs. An A SKU can only be used for the embed for your customers solution.
A Power BI workspace with a report.
Your own Microsoft Entra tenant.
A .NET Core 5 model view controller (MVC) app.
.NET Core 5 SDK (or higher).
An integrated development environment (IDE). We recommend using one of the following environments:
- Visual Studio.
- Visual Studio Code (with the C# extension).
Resources
In this tutorial, you use:
- Power BI REST Reports API - to embed the URL and retrieve the embed token.
- Microsoft Identity Web authentication library.
- Power BI embedded analytics Client APIs - to embed the report.
Method
To embed Power BI content in an embed for your organization solution, follow these steps:
- Configure your Microsoft Entra app
- Get the embedding parameter values
- Add the required NuGet packages
- Enable server side authentication
- Build your app's client side
- Run your application
Step 1 - Configure your Microsoft Entra app
When your web app calls Power BI, it needs an Microsoft Entra token to call Power BI REST APIs and embed Power BI items such as reports, dashboards, or tiles.
If you don't have a Microsoft Entra app, create one using the instructions in Register a Microsoft Entra application to use with Power BI.
To configure your Microsoft Entra app, follow the instructions in Configure your Microsoft Entra app.
Step 2 - Get the embedding parameter values
To embed your report, you need the following values:
Domain and tenant ID
If you don't know your domain or tenant ID, see Find the Microsoft Entra tenant ID and primary domain name.
Note
To embed content for a user on a different tenant (a guest user), you need to adjust the authorityUri
parameter.
Client ID
To get the client ID GUID (also know as application ID), follow these steps:
Log into Microsoft Azure.
Search for App registrations and select the App registrations link.
Select the Microsoft Entra app you're using for embedding your Power BI content.
From the Overview section, copy the Application (client) ID GUID.
Client secret
To get the client secret, follow these steps:
Log into Microsoft Azure.
Search for App registrations and select the App registrations link.
Select the Microsoft Entra app you're using for embedding your Power BI content.
Under Manage, select Certificates & secrets.
Under Client secrets, select New client secret.
In the Add a client secret pop-up window, provide a description for your application secret, select when the application secret expires, and select Add.
From the Client secrets section, copy the string in the Value column of the newly created application secret. The client secret value is your client ID.
Note
Make sure you copy the client secret value when it first appears. After navigating away from this page, the client secret will be hidden and you'll not be able to retrieve its value.
Workspace ID
To get the workspace ID GUID, follow these steps:
Sign in to Power BI service.
Open the report you want to embed.
Copy the GUID from the URL. The GUID is the number between /groups/ and /reports/.
Note
To get the workspace ID programmatically, use the Get Groups API.
Report ID
To get the report ID GUID, follow these steps:
Sign in to Power BI service.
Open the report you want to embed.
Copy the GUID from the URL. The GUID is the number between /reports/ and /ReportSection.
Note
To get the report ID programmatically, use the Get Reports In Group API.
Step 3 - Add the required NuGet packages
Before you start, you need to add the Microsoft.Identity.Web
, and Microsoft.PowerBI.Api
NuGet packages to your app.
Add the following NuGet packages to your app:
In VS Code, open a terminal and type in the following code.
In Visual studio, navigate to Tools > NuGet Package Manager > Package Manager Console and type in the following code.
dotnet add package Microsoft.Identity.Web -v 0.3.0-preview
dotnet add package Microsoft.Identity.Web.UI -v 0.3.0-preview
dotnet add package Microsoft.PowerBI.Api
If your app previously used Microsoft.AspNetCore
to authenticate, remove this package from your project by typing:
dotnet remove package Microsoft.AspNetCore.Authentication.AzureAD.UI
Step 4 - Enable server-side authentication
Enable server-side authentication in your app, by creating or modifying the files in the following table.
File | Use |
---|---|
Startup.cs | Initialize the Microsoft.Identity.Web authentication service |
appsettings.json | Authentication details |
PowerBiServiceApi.cs | Get the Microsoft Entra token and embedding metadata |
HomeController.cs | Pass embedding data as a model to the view |
Configure your startup file to support Microsoft.Identity.Web
Modify the code in Startup.cs to properly initialize the authentication service provided by Microsoft.Identity.Web
.
Add the following code snippet to your app's Startup.cs file.
Note
The code in ConfigureServices
accomplishes several important things:
- The call to
AddMicrosoftWebAppCallsWebApi
configures the Microsoft Authentication Library to acquire access tokens (Microsoft Entra tokens). - The call to
AddInMemoryTokenCaches
configures a token cache that the Microsoft Authentication Library will use to cache access tokens and refresh tokens behind the scenes - The call to
services.AddScoped(typeof(PowerBiServiceApi))
configures thePowerBiServiceApi
class as a service class that can be added to other classes using dependency injection.
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.Identity.Web.UI;
using UserOwnsData.Services;
namespace UserOwnsData {
public class Startup {
public Startup (IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices (IServiceCollection services) {
services
.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(PowerBiServiceApi.RequiredScopes)
.AddInMemoryTokenCaches();
services.AddScoped (typeof (PowerBiServiceApi));
var mvcBuilder = services.AddControllersWithViews (options => {
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add (new AuthorizeFilter (policy));
});
mvcBuilder.AddMicrosoftIdentityUI();
services.AddRazorPages();
}
}
}
Create an authentication details file
In this tutorial, the appsettings.json
file contains sensitive information such as client ID and client secret. For security reasons, we don't recommend keeping this information in the settings file. When embedding in your application, consider a more secure method such as Azure Key Vault for keeping this information.
In your project, create a new file and call it appsettings.json.
Add the following code to appsettings.json:
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "", "TenantId": "", "ClientId": "", "ClientSecret": "", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath": "/signout-callback-oidc" }, "PowerBi": { "ServiceRootUrl": "https://api.powerbi.com" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
Fill in the embedding parameter values obtained from Step 2 - Get the embedding parameter values.
Domain
- Domain and tenant IDTenantId
- Domain and tenant IDClientId
- Client IDClientSecret
- Client secret
Note
In the previous code snippet, the PowerBi:ServiceRootUrl
parameter is added as a custom configuration value to track the base URL to the Power BI service. When programming against the Power BI service in the Microsoft public cloud, the URL is https://api.powerbi.com/
. However, the root URL for the Power BI service will be different in other clouds such as the government cloud. Therefore, this value is stored as a project configuration value so it is easy to change when required.
Get the Microsoft Entra access token and call the Power BI service
In order to embed Power BI content (such as reports and dashboards), your app needs to get an Microsoft Entra token. To get the token, you need a configuration object.
The code in this section uses the .NET Core dependency injection pattern. When your class needs to use a service, you can add a constructor parameter for that service and the .NET Core runtime takes care of passing the service instance at run time. In this case, the constructor is injecting an instance of the .NET Core configuration service using the IConfiguration
parameter, which is used to retrieve the PowerBi:ServiceRootUrl
configuration value from appsettings.json. The ITokenAcquisition
parameter, which is named tokenAcquisition
holds a reference to the Microsoft authentication service provided by the Microsoft.Identity.Web
library and is used to acquire access tokens from Microsoft Entra ID.
The RequiredScopes
field holds a string array containing a set of delegated permissions supported by the Power BI service API. When your application calls across the network to acquire a Microsoft Entra token, passes this set of delegated permissions so that Microsoft Entra ID can include them in the access token it returns.
Note
Verify that your Microsoft Entra app is configured with the scopes required by your web app. For more information, see Change your Microsoft Entra app's permissions.
In your app's project, create a new folder titled Services.
In the Services folder, create a new file titled PowerBiServiceApi.cs.
Add the following code to PowerBiServiceApi.cs.
using Microsoft.Identity.Web; using Microsoft.PowerBI.Api; using Microsoft.PowerBI.Api.Models; using Microsoft.Rest; using Newtonsoft.Json; namespace UserOwnsData.Services { // A view model class to pass the data needed to embed a single report. public class EmbeddedReportViewModel { public string Id; public string Name; public string EmbedUrl; public string Token; } public class PowerBiServiceApi { private ITokenAcquisition tokenAcquisition { get; } private string urlPowerBiServiceApiRoot { get; } public PowerBiServiceApi(IConfiguration configuration, ITokenAcquisition tokenAcquisition) { this.urlPowerBiServiceApiRoot = configuration["PowerBi:ServiceRootUrl"]; this.tokenAcquisition = tokenAcquisition; } public static readonly string[] RequiredScopes = new string[] { "https://analysis.windows.net/powerbi/api/Report.Read.All" }; // A method to get the Azure AD token (also known as 'access token') public string GetAccessToken() { return this.tokenAcquisition.GetAccessTokenForUserAsync(RequiredScopes).Result; } public PowerBIClient GetPowerBiClient() { var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer"); return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot), tokenCredentials); } public async Task<EmbeddedReportViewModel> GetReport(Guid WorkspaceId, Guid ReportId) { PowerBIClient pbiClient = GetPowerBiClient(); // Call the Power BI Service API to get embedding data var report = await pbiClient.Reports.GetReportInGroupAsync(WorkspaceId, ReportId); // Return report embedding data to caller return new EmbeddedReportViewModel { Id = report.Id.ToString(), EmbedUrl = report.EmbedUrl, Name = report.Name, Token = GetAccessToken() }; } } }
Modify the HomeController.cs file
In this code example, you use dependency injection. As you registered the PowerBiServiceApi
class as a service by calling services.AddScoped
in the ConfigureServices
method. You can add a PowerBiServiceApi
parameter to the constructor, and the .NET Core runtime takes care of creating a PowerBiServiceApi
instance and passing it to the constructor.
From the Controllers folder, open the HomeController.cs file and add it to the following code snippet:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using UserOwnsData.Models;
using UserOwnsData.Services;
namespace UserOwnsData.Controllers {
[Authorize]
public class HomeController : Controller {
private PowerBiServiceApi powerBiServiceApi;
public HomeController (PowerBiServiceApi powerBiServiceApi) {
this.powerBiServiceApi = powerBiServiceApi;
}
[AllowAnonymous]
public IActionResult Index() {
return View();
}
public async Task<IActionResult> Embed() {
Guid workspaceId = new Guid("11111111-1111-1111-1111-111111111111");
Guid reportId = new Guid("22222222-2222-2222-2222-222222222222");
var viewModel = await powerBiServiceApi.GetReport(workspaceId, reportId);
return View(viewModel);
}
[AllowAnonymous]
[ResponseCache (Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error() {
return View (new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Step 5 - Build your app's client side
For client-side implementation, you need to create or modify the files in the following table.
File | Use |
---|---|
embed.js | Contains the client-side JavaScript code |
Embed.cshtml | Contains your app's document object model (DOM), and a DIV for embedding the report |
Create a container for your embedded report
Create the Embed.cshtml file, which has a div
element used as a container for your embedded report, and three scripts.
In the View > Home folder, create a file called Embed.cshtml.
Add the following code snippet to the Embed.cshtml file.
@model UserOwnsData.Services.EmbeddedReportViewModel; <div id="embed-container" style="height:800px;"></div> @section Scripts { <!-- powerbi.min.js is the JavaScript file that loads the client-side Power BI JavaScript API library. Make sure that you're working with the latest library version. You can check the latest library available in https://cdnjs.com/libraries/powerbi-client --> <script src="https://cdn.jsdelivr.net/npm/powerbi-client@2.21.0/dist/powerbi.min.js"></script> <!-- This script creates a JavaScript object named viewModel which is accessible to the JavaScript code in embed.js. --> <script> var viewModel = { reportId: "@Model.Id", embedUrl: "@Model.EmbedUrl", token: "@Model.Token" }; </script> <!-- This script specifies the location of the embed.js file --> <script src="~/js/embed.js"></script> }
Add client-side JavaScript to embed your report
To embed Power BI content, you need to create a configuration object. To learn more about creating the configuration object, see Embed a report.
In this section, you create a JavaScript file named embed.js with a configuration object for embedding your report, using the variable models
.
models
is initialized using a call to window['powerbi-client'].models
. The models
variable is used to set configuration values such as models.Permissions.All
, models.TokenType.Aad
, and models.ViewMode.View
.
The powerbi.embed
function uses the models
configuration object to embed your report.
In the wwwroot > js folder, create a file called embed.js.
Add the following code snippet to the embed.js file.
$(function(){ // 1 - Get DOM object for div that is report container let reportContainer = document.getElementById("embed-container"); // 2 - Get report embedding data from view model let reportId = window.viewModel.reportId; let embedUrl = window.viewModel.embedUrl; let token = window.viewModel.token // 3 - Embed report using the Power BI JavaScript API. let models = window['powerbi-client'].models; let config = { type: 'report', id: reportId, embedUrl: embedUrl, accessToken: token, permissions: models.Permissions.All, tokenType: models.TokenType.Aad, viewMode: models.ViewMode.View, settings: { panes: { filters: { expanded: false, visible: true }, pageNavigation: { visible: false } } } }; // Embed the report and display it within the div container. let report = powerbi.embed(reportContainer, config); // 4 - Add logic to resize embed container on window resize event let heightBuffer = 12; let newHeight = $(window).height() - ($("header").height() + heightBuffer); $("#embed-container").height(newHeight); $(window).resize(function() { var newHeight = $(window).height() - ($("header").height() + heightBuffer); $("#embed-container").height(newHeight); }); });
Step 6 - Run your application
After you've made all the adjustments listed in this tutorial, you're ready to run your application. Execute your application and experiment with the way your Power BI report is embedded. You can use the Power BI embedded analytics Client APIs to enhance your app using client side APIs.
When your app is ready, you can move your embedded app to production.