EnableYourData.nl

Resources · Power BI

What is row-level security (RLS) in Power BI?

Row-level security (RLS) in Power BI is a security layer in the semantic model that determines which rows of data a user gets to see. Everyone opens the same report, but a regional manager only sees their own region and a customer only their own orders. You define RLS in roles with DAX filters: static with fixed values, or dynamic based on who is viewing.

Key takeaways

  • RLS filters rows in the semantic model, so it applies to every report built on that model.
  • Static RLS uses fixed values per role; dynamic RLS filters on the signed-in user, usually with USERPRINCIPALNAME().
  • With Power BI Embedded, the application passes the identity in the embed token, optionally with an extra value that you read with CUSTOMDATA().
  • RLS only applies to viewers; workspace Members, Contributors and Admins see all data.
  • A secure set-up has no fallback: anyone without a role or tag sees nothing.

How row-level security works in Power BI

Row-level security is a form of role-based access to data: a user's role determines which rows they see. In Power BI Desktop, you go to Modeling and choose Manage roles to create one or more roles. For each role, you write a DAX filter on a table, for example [Region] = "North". The filter is evaluated row by row; only rows for which the result is true remain visible.

The filter propagates through the relationships in your model to related tables. If you filter the Customer dimension, the orders and invoices of other customers are hidden as well. After publishing, you assign users or security groups to the roles in the Power BI service, in the security settings of the semantic model.

Because RLS lives in the model, it applies to every report and every analysis on that model, including when someone analyses the data in Excel. RLS restricts rows, not tables or columns. If you want to hide entire columns or tables, you need object-level security.

Static and dynamic RLS

With static RLS, the filter value is fixed in the role. You might create the roles North, East, South and West, for example, each with its own filter. With dynamic RLS, there is often just one role, and the filter depends on who is viewing.

A common set-up for dynamic RLS is an access table with an email address and a region or customer on each row. The role filter on that table is then [Email] = USERPRINCIPALNAME(). Pay attention to the direction of the relationship: the filter must be able to flow from the access table to your dimension. If it cannot, you can apply the security filter in both directions on the relationship, or write the filter directly on the dimension.

Static RLSDynamic RLS
FilterFixed value per role, such as [Region] = "North"Depends on the user, via USERPRINCIPALNAME() or CUSTOMDATA()
Number of rolesOne role per variantOften one role for everyone
ManagementA new region means a new roleA new user means a new row in the access table
Suitable forA few stable groupsMany users or customers, changing access

USERPRINCIPALNAME() and USERNAME()

USERPRINCIPALNAME() returns the user principal name (UPN) of the signed-in user, usually in the form name@company.com. In the Power BI service, USERNAME() returns the same value, but in Power BI Desktop it returns the form DOMAIN\user. So preferably use USERPRINCIPALNAME(), so that your filter works the same way in Desktop and in the service.

A UPN is not always the same as the email address in your access table, for example with aliases or after a name change. Check this before you go live. With Power BI Embedded in the "app owns data" scenario, both functions return the username that the application passes in the embed token.

RLS with Power BI Embedded: effective identity and CUSTOMDATA

In a customer portal, the end user does not sign in to Microsoft. The application signs in with a service principal, which itself is allowed to see all data. That is why the application passes an effective identity when it requests the embed token: a username, one or more roles and the semantic model. Power BI applies the RLS rules for that identity. If a model has RLS, Power BI will not issue an embed token without an identity.

Besides the username, you can pass a free-text value: customData. In a role filter, you read it with the DAX function CUSTOMDATA(), for example [CustomerCode] = CUSTOMDATA(). This is useful when your portal's users are not in your Microsoft Entra ID and you want to filter on an attribute that is managed in the portal, such as a customer number or branch. It also means the application is fully responsible for the correct value: a mistake in that mapping is a data breach.

In ENABLE, you link access profiles or a user tag to Power BI roles, optionally with CUSTOMDATA(). If a user has no tag, they get no access: ENABLE never falls back to unfiltered data. RLS is off by default and is switched on per customer.

Testing RLS before you go live

Always test row-level security with real user scenarios, not just with the role you have just created. In ENABLE, an administrator can also use "Preview as user" to check what a specific user gets to see. A practical order:

  1. In Power BI Desktop, use the View as option: choose a role and, for dynamic RLS, another user with a UPN from your access table.
  2. After publishing, test in the Power BI service through the security settings of the semantic model with Test as role, optionally as a specific user.
  3. Test the edge cases: a user without a row in the access table, a user with several regions, a new customer and an employee who has left.
  4. Check totals and cards. A measure with ALL() does not escape the RLS filter, but a table without a relationship to the filtered table is not filtered at all.
  5. In a portal, test the whole chain, from sign-in to embed token, and not just the model.

Common mistakes with row-level security

Most problems with RLS are not in the DAX formula, but in the set-up around it. Watch out for these pitfalls:

  • Readers with the Member, Contributor or Admin role in the workspace. RLS does not apply to them; give readers the Viewer role or share through an app.
  • Tables without a relationship to the filtered table. These are not filtered and therefore show all rows.
  • No deliberate choice for users without a role. The secure starting point is: no role or tag means no data.
  • An outdated access table. RLS is only as good as the mapping between users and data; leavers and changes must be kept up to date.
  • Relying on hidden filters or slicers in the report. That is presentation, not security.
  • Complex DAX in role filters on large fact tables. Preferably filter on small dimension tables; that is faster and easier to check.

FAQ

Frequently asked questions

What is row-level security in Power BI?

Row-level security (RLS) is a security feature in a Power BI semantic model that determines per user which rows of data are visible. You create roles with DAX filters and assign users or groups to those roles. That way, everyone can use the same report and still see only their own data.

What is the difference between static and dynamic RLS?

With static RLS, the filter value is fixed in the role, for example one role per region. With dynamic RLS, the filter depends on the signed-in user, usually via USERPRINCIPALNAME() and an access table. Dynamic RLS is easier to manage with many users or customers.

Does row-level security also apply to workspace admins?

No. In the Power BI service, RLS only applies to users with the Viewer role in the workspace. Admins, Members and Contributors see all data. So share reports with readers through an app or give them the Viewer role.

Does RLS work with Power BI Embedded?

Yes. When embedding for your customers, the application passes an effective identity in the embed token with a username and one or more roles. Power BI applies the RLS rules for that identity. Optionally, the application can pass an extra value that you read in DAX with CUSTOMDATA().

What does CUSTOMDATA() do in Power BI?

CUSTOMDATA() is a DAX function that returns a free-text value an application passes in the embed token when embedding a report. You use it in a role filter, for example [CustomerCode] = CUSTOMDATA(), to filter on an attribute managed in your portal rather than on an email address.

How do you test row-level security in Power BI?

In Power BI Desktop, you use View as to simulate a role and, optionally, another user. In the Power BI service, you test through the security settings of the semantic model with Test as role. Also test edge cases, such as a user without a role or with several regions.

Share securely, live fast, no headache

In an online demo we show you the portal: dashboards per role, row-level security, plain-language questions and how we set it up and manage it for you.