Saturday, December 17, 2016

Embedding PBI Tiles with Security


Bring the power of PowerBI into our application


Embedding PBI reports and tiles into web apps is a desired way of sharing data visualizations. Business users can view and interact with data graphs from within their application without the hassle to manage accounts with other systems. Currently PBI has an Publish to Web option that is good for deliver contents that intents to the public, or in a testing scenario, but most often we need authentication for those contents. This writing is to briefly describe the steps of embedding PBI tiles and reports with authentication.



(Source: https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-integrate-tile/)

Register the app

First, we need to register our web application with PowerBI. This can be simply done in this web page Register an Application for Power BI (Power BI for Developers). The registration process requires the Redirect URL and the Home Page URL, it then generates the Client ID and the Client Secret (following screenshot). The Redirect URL tells PBI where to send the Access Code; the Home URL provides PBI the domain where requests will be made from. In addition, in the registeration we can set access level for the contents.



Nevertheless, this page is just quick way for registering applications. For tracking and managing registrations we need to login to Azure portal, the AD (Active Directory) section.

Use the REST API

From this Power BI API (Apiary Powered Documentation) website we can retrieve list of Dashboards, collection of Tiles in a Dashboard, list of Reports and more (such as Datasets, Tables, Table Rows, Data Source Collection, Imports, Gateways, Groups, Connection Strings). I.e., we can access all objects in PowerBI with this RESTful API.

This is very useful when we need to specify what tiles or reports are to be embedded in a web page, because the API returns the object ids. Other than we need dynamically decide the tiles or reports to be embedded, in which case we need to have own code retrieving those PBI objects, we can use this website to get the ids we need.

Notice, don't be confused with the "login with Apiary" on the website, that is only required if we want register with Apiary. But we do need to have logged in PBI so that it knows what account to access.

The Sequence of Access

In coding, we need a few steps. First, get the Access Code, then get the Access Token, and finally request a tile or a report with the Access Token.

1. Send a request for the Authorization Code. This request is sent to https://login.windows.net/common/oauth2/authorize in a HTTP GET, with following paramters:
client_id: "{we got from application registration}"
resource: "https://analysis.windows.net/powerbi/api"
redirect_uri: "{where to the HTTP Response is sent to, we provided in the application registration}"

Notice that requesting for Authority Code doesn't need Client Secret.

2. Request for Access Token
This request is made to https://login.windows.net/common/oauth2/authorize,
through AuthenticationContext class (assembly: Microsoft.IdentityModel.Clients.ActiveDirectory).

var tc = new TokenCache();
var authority = "https://login.windows.net/common/oauth2/authorize";
var ac = new AuthenticationContext(authority, tc);
var cc = new ClientCredential(_clientId, _clientSecret);

//Set token from authentication result
return (await AC.AcquireTokenByAuthorizationCodeAsync(authorizationCode, new Uri(_redirectUrl), cc)).AccessToken;

Notice the token cache, where we can store received token for later use. check this link Here for details.

3. Render HTML with embeded IFrame
When we have the Access Token ready and we know the id of the tile or report to embed in a iframe, the code is simple, e.g.,
var iframe = document.getElementById('{ID of the iFrame for embedding a Tile});
iframe.src = "https://app.powerbi.com/embed?dashboardId={"we get from REST API website"};

 var messageStructure = {
            action: "loadTile",
            accessToken: '@ViewBag.AccessToken',
            height: 500,
            width: 500
        };

iframe.contentWindow.postMessage(msg, "*");

See more code examples https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-integrate-tile-code/

Understand and manage the Access Code and the Access Token


We need an Access Token to access PBI resources. But to an Access Token, we need to get an Access Code first. That can be acquired by providing the Client Id and the Client Secret that we have acquired in the application registration step.

Why don't get the Access token directly from the Client Id and the Client Secret while doing a detour to the Access Code? as explained here https://powerbi.microsoft.com/en-us/documentation/powerbi-developer-power-bi-permissions/, because the Access Code is given through HTTP response and that bears security risk. The application has to exchange it for an Access Token. In addition, as the best practice, we need to set/manage expiry for the the Access Code. For further research about the content of an Access Code, check here: https://docs.microsoft.com/en-us/azure/power-bi-embedded/power-bi-embedded-app-token-flow

P.S.
Managing expiry of the Access Code should be a separate component in our web application. Then user sessions or view state can be populated from the the separated component when needed.