Power BI Advanced Series · Power BI Embedding & Security · by Raushan Ranjan, MCT
This guide provides a focused deep dive into two critical aspects of Power BI embedding: designing Row-Level Security (RLS) within the "App-Owns-Data" model and the process of generating RLS-restricted embed tokens. This is essential for delivering personalized and secure data experiences within your custom web applications.
📌 1. Designing for RLS with the App-Owns-Data Model
🧠 What is RLS (Row-Level Security)?
RLS (Row-Level Security) is a powerful feature in Power BI that filters the data a user can see based on their identity or role. Instead of giving everyone access to the full dataset, you can define rules to show only the relevant rows of data to each user, ensuring data governance and privacy.
🧠 What is App-Owns-Data Model?
In this model:
- Your application controls the authentication (not the Power BI service directly).
- Users of your application typically don’t need a Power BI account or license.
- Your app embeds the report and generates a secure embed token on behalf of the user.
- You can precisely control what data each user sees by applying RLS through the embed token.
✅ Designing for RLS in this model
To design RLS for the App-Owns-Data model, you define roles and filters within Power BI Desktop, and then your application's backend will tell Power BI which role to apply.
| Step | Description |
|---|---|
| 1️⃣ Define Roles | Inside Power BI Desktop, use Modeling > Manage Roles to create one or more roles (e.g., "EastRegionRole", "SalesRole"). |
| 2️⃣ Create DAX Filter | For each role, create a DAX filter expression that determines which rows are visible. This filter will typically reference a column in your data model. For dynamic filtering based on the embed token's `username`, use USERNAME() or USERPRINCIPALNAME(). |
| 3️⃣ Publish Report | Publish the report to a Power BI Workspace that is backed by a Power BI Premium or Embedded capacity. |
| 4️⃣ Pass Identity & Role | In your backend, when generating the embed token, you'll pass the user identity (via `username`) and the RLS role(s) to apply using the `EffectiveIdentity` object. |
| 5️⃣ Power BI Applies Filter | Power BI receives the embed token, applies the specified role-based filter to the dataset, and then renders the report to that user with only the authorized data. |
👩💻 Example:
In Power BI Desktop:
- Role:
EastRegionRole - DAX Filter:
[Region] = "East"
When embedding, your C# backend code would specify this role:
var identity = new EffectiveIdentity("raushan@demo.com", new List<string> { datasetId })
{
Roles = new List<string> { "EastRegionRole" }
};
This ensures only "East Region" data is shown for the user associated with "raushan@demo.com".
📌 2. Generating Embed Tokens Restricted by RLS Roles
🧠 Why Generate Embed Tokens?
Embed Tokens are short-lived, secure keys used by your application to securely display Power BI reports without exposing any Power BI credentials. Each token contains specific information about:
- What report to load.
- What dataset to use.
- What access level is allowed (e.g., View, Edit, Create).
- Crucially, what RLS role(s) to apply (if any).
✅ Steps to Generate RLS-Sensitive Embed Tokens
| Step | Description |
|---|---|
| 1️⃣ Authenticate Backend | Use your Azure AD App (Service Principal) to authenticate your backend application with Azure AD. This grants your app access to Power BI APIs. |
| 2️⃣ Call Power BI REST API | Use the Power BI .NET SDK (or directly call the REST API) to interact with the Power BI Service. |
3️⃣ Create EffectiveIdentity |
Create an EffectiveIdentity object. This object tells Power BI "who" the user is (via `username`) and "which RLS role(s)" should apply to them. You also specify the `datasetId` this identity applies to. |
| 4️⃣ Build Token Request | Pass this `EffectiveIdentity` object within a `GenerateTokenRequestV2` (or similar) object. You also specify the report ID, dataset ID, and desired access level. |
| 5️⃣ Get Token | Call the Power BI API's `GenerateTokenAsync` (or `GenerateTokenInGroupAsync`) method to retrieve the embed token. |
👨💻 Sample C# Code:
This snippet demonstrates how to construct the `EffectiveIdentity` and the token generation request in C# using the Power BI .NET SDK.
// Assume 'datasetId', 'reportId', 'workspaceId' are Guids obtained from Power BI Service
// Assume 'pbiClient' is an authenticated PowerBIClient instance
var effectiveIdentity = new EffectiveIdentity("raushan@demo.com", new List<string> { datasetId.ToString() })
{
Roles = new List<string> { "EastRegionRole" } // RLS role defined in Power BI Desktop
};
var tokenRequest = new GenerateTokenRequestV2
{
Reports = new List<GenerateTokenRequestV2Report>
{
new GenerateTokenRequestV2Report { Id = Guid.Parse(reportId) }
},
Datasets = new List<GenerateTokenRequestV2Dataset>
{
new GenerateTokenRequestV2Dataset { Id = Guid.Parse(datasetId) }
},
Identities = new List<EffectiveIdentity> { effectiveIdentity },
AccessLevel = "View"
};
var embedToken = await pbiClient.EmbedToken.GenerateTokenInGroupAsync(
Guid.Parse(workspaceId),
tokenRequest
);
⚠ Important Notes
- The `username` provided in the `EffectiveIdentity` **does not need to be a real Power BI user account**. It's a string identifier that Power BI's `USERNAME()` or `USERPRINCIPALNAME()` DAX functions will return. This allows you to integrate with your own application's user management system.
- Make sure the `role` names in the `EffectiveIdentity` (e.g.,
"SalesRole"or"EastRegionRole") **exactly match** those defined in your Power BI Desktop file (case-sensitive). - Embed tokens are typically valid for **1 hour**. Your application should handle token refreshing before expiration to provide a continuous experience.
🎯 Summary (TL;DR)
| Concept | Meaning |
|---|---|
| RLS | Filters data per user using roles defined in Power BI Desktop. |
| App-Owns-Data | Your application authenticates with Power BI, and end-users don’t need Power BI accounts. |
| EffectiveIdentity | A crucial object in the embed token request that tells Power BI "who" the user is (`username`) and "which role" applies. |
| Embed Token | Short-term secure token that controls what the user sees and which RLS filters are applied. |
Quick Knowledge Check
Q1. To apply Row-Level Security in an app-owns-data embedded report, how do you restrict data to the currently logged-in user of your application?
Show Answer
Pass an effective identity in the embed token request. When calling the Power BI REST API to generate an embed token, include an EffectiveIdentity object with the user's identifier (e.g., email or username) and the relevant dataset ID. Power BI applies the RLS role whose DAX filter evaluates USERNAME() or USERPRINCIPALNAME() against the value you supply. The report only returns data rows matching that identity — the application never sees rows for other users.
Q2. You generate an embed token for report X using a service principal. The report uses RLS but you forget to pass an effective identity. What happens?
- A) The embed fails with a 403 error because service principals cannot use RLS
- B) The embedded report shows ALL data — RLS is not applied when no effective identity is provided
- C) Power BI automatically uses the service principal's Azure AD identity as the RLS filter
- D) The report shows an empty dataset because RLS defaults to restricting everything
Show Answer
B. When no effective identity is passed, the service principal's embed token bypasses RLS — all data is returned. This is a critical security bug: embedding with a service principal requires you to ALWAYS pass an effective identity for RLS datasets. Power BI does not auto-apply RLS for service principals; it trusts the application to specify the user context.
Q3. What is the difference between a static RLS role and a dynamic RLS role in Power BI?
Show Answer
Static RLS uses a hardcoded DAX filter that restricts data to a fixed value (e.g., [Region] = "North"). Dynamic RLS uses the USERNAME() or USERPRINCIPALNAME() function to filter based on the currently logged-in user. In app-owns-data embedding, dynamic RLS is typically used: the effective identity passed in the embed token is compared against a lookup table (e.g., UserPermissions) that maps user emails to their allowed data. Static roles are used when a group of users always sees the same fixed subset (e.g., a regional manager role).
5 Things to Remember
- Effective identity in the embed token applies RLS — pass the user's email/username when generating the token. Without it, a service principal bypasses RLS and returns all data.
- Dynamic RLS uses USERNAME() or USERPRINCIPALNAME() — DAX filter compares the effective identity to a user-permission table, restricting rows per user without creating a separate role per person.
- Static RLS uses hardcoded DAX filters — suitable when a named group always sees the same data slice. Requires managing role assignments in Power BI Desktop.
- Service principals bypass RLS by default — always pass effective identity for any dataset with RLS. Missing effective identity is a serious security vulnerability in embedded apps.
- Test RLS in Power BI Desktop before embedding — use "View as role" to verify the DAX filter produces the correct row subset before deploying. Bugs in RLS expressions are hard to diagnose in embedded scenarios.
Quick Knowledge Check
Q1. To apply Row-Level Security in an app-owns-data embedded report, how do you restrict data to the currently logged-in user of your application?
Show Answer
Pass an effective identity in the embed token request. When calling the Power BI REST API to generate an embed token, include an EffectiveIdentity object with the user's identifier (e.g., email or username) and the relevant dataset ID. Power BI applies the RLS role whose DAX filter evaluates USERNAME() or USERPRINCIPALNAME() against the value you supply. The report only returns data rows matching that identity — the application never sees rows for other users.
Q2. You generate an embed token for report X using a service principal. The report uses RLS but you forget to pass an effective identity. What happens?
- A) The embed fails with a 403 error because service principals cannot use RLS
- B) The embedded report shows ALL data — RLS is not applied when no effective identity is provided
- C) Power BI automatically uses the service principal's Azure AD identity as the RLS filter
- D) The report shows an empty dataset because RLS defaults to restricting everything
Show Answer
B. When no effective identity is passed, the service principal's embed token bypasses RLS — all data is returned. This is a critical security bug: embedding with a service principal requires you to ALWAYS pass an effective identity for RLS datasets. Power BI does not auto-apply RLS for service principals; it trusts the application to specify the user context.
Q3. What is the difference between a static RLS role and a dynamic RLS role in Power BI?
Show Answer
Static RLS uses a hardcoded DAX filter that restricts data to a fixed value (e.g., [Region] = "North"). Dynamic RLS uses the USERNAME() or USERPRINCIPALNAME() function to filter based on the currently logged-in user. In app-owns-data embedding, dynamic RLS is typically used: the effective identity passed in the embed token is compared against a lookup table (e.g., UserPermissions) that maps user emails to their allowed data. Static roles are used when a group of users always sees the same fixed subset (e.g., a regional manager role).
- Effective identity in the embed token applies RLS — pass the user's email/username when generating the token. Without it, a service principal bypasses RLS and returns all data.
- Dynamic RLS uses USERNAME() or USERPRINCIPALNAME() — DAX filter compares the effective identity to a user-permission table, restricting rows per user without creating a separate role per person.
- Static RLS uses hardcoded DAX filters — suitable when a named group always sees the same data slice. Requires managing role assignments in Power BI Desktop.
- Service principals bypass RLS by default — always pass effective identity for any dataset with RLS. Missing effective identity is a serious security vulnerability in embedded apps.
- Test RLS in Power BI Desktop before embedding — use "View as role" to verify the DAX filter produces the correct row subset before deploying. Bugs in RLS expressions are hard to diagnose in embedded scenarios.