Row Level Security for Embedded PowerBI Reports with Service Principal Authentication

To present a PowerBI report user or consumer with a securely pre-filtered dataset, row level security must be used. In a PowerBI embedded architecture where “app owns data”, implementing row level security (RLS) requires a modification to the token generation request. By specifying a role and user in the token request, we can generate an embed token specific to the user’s data access.


The application of RLS to PowerBI in an embedded scenario requires a 2-part change from the vanilla embed scenario. With the goal of embedding a report with row level security enforced, we must make changes to the embed token generation as well as to the report in PowerBI desktop.

Chart tying PowerBI desktop functionality to embed token generation

Obtaining a User/Role-Specific Embed Token

We’re going to start from the .Net Core example for generating an embed token (Blog Post | Repository). At line 61 we adjust the GenerateTokenRequest function to take in a new parameter, an EffectiveIdentity. Our GenerateTokenRequest goes from:

var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");


var generateTokenRequestParameters = new GenerateTokenRequest(
    "View", // access level
    identities: new List<EffectiveIdentity> { new EffectiveIdentity(
        username: "PutTheUserNameHere", 
        roles: new List<string> { "RoleNameHereThisIsDefinedPerReport"}, 
        datasets: new List<string> { report.DatasetId }

If your code (like the sample) does not already include list structures, you will need to add a reference to System.Collections.Generic with this adjustment. Other necessary changes to your code include likely input parameters for the userID of the runtime user, potentially the role(s) as well.

Preparing a Report for Row Level Security in PowerBI Desktop

Without diving too far into the structure of your data, we’re going to play with a sample model so simple that it is a single table. This model fulfills the most important constraint for row level security – a field that can be used in a DAX expression to validate access by user or by role – in this case by including a single column for the user’s identifier.

Simple dataset with userid, email, jobcode, job description, and status columns

Super Simple Dataset for RLS

Back in the PowerBI report designer view under the Modeling tab, we find an option for Manage Roles. We are creating a single role called “Users” and it filters the single table in our dataset with the expression [USERID] = username(), that is the column USERID must equal the username.

PowerBI desktop window with manage roles dialog box open to DAX expression

Filter by DAX Expression in Manage Roles

Note! When you view the report in PowerBI desktop and a role is not applied to your user, RLS is not enforced. The view-as functionality can be useful to apply the RLS of a specific role. In the example below, no rows match the username ‘DSK-LAPTOP\drewk’ when the role ‘Users’ is applied.

No RLS, 114 Rows in the Dataset
RLS for ‘Users’ Role

Tip! Want to know what username is being used at report runtime? Add a measure to your dataset for RUNTIMEUSERID = username() and add the measure to a card visual.

The Resulting Row Level Security

A GUID-style username is passed to the report at runtime along with the role name ‘Users’, matching a subset of the rows. The resulting dataset and report embed token have RLS enforced, displaying only 57 of the total 114 rows.