Skip to content
Power BI Analytics

row-level-security

Power BI Row-Level Security: A Definitive Guide

The working guide for Power BI row-level security: how roles actually filter, how to map Entra groups, how to test, and why Desktop success is not production success.

NDA-readyFixed-scope first releaseBusiness + IT handover
Executive Power BI scorecard with KPI tiles and trend sparklines
  • Operating since 2012
  • Microsoft Power BI specialists
  • NDA-ready data handling
  • Fixed-scope first releases
  • Independent — not affiliated with Microsoft
August 14, 20267 min readBy Power BI Analytics Team

Row-level security in Power BI is a filter on the model, evaluated when a user opens a report. It is not a workspace permission, not an app audience, and not a hide-page bookmark. If you treat those as substitutes, you will either leak rows or ship blank visuals and call it a refresh bug.

Logistics teams need it so a 3PL customer does not see another shipper’s freight. Healthcare teams need it so a unit manager does not receive another facility’s census. Manufacturing teams need it so a plant manager does not browse another site’s scrap. Same mechanism, different bridge tables. This guide is the shared technical standard those industry pages should link to.

What RLS actually filters

Each role is a DAX filter expression on one or more tables. When the role is active, those filters propagate along relationships the same way a slicer would. If the role filters a disconnected helper table, the fact is unchanged and you have a leak. If the role filters a table that has no path to the visual’s data, you get blanks. Validate with a fact-row count visual under View as — not only a card on the dimension.

Workspace Admin, Member, and Contributor can see the dataset without RLS applying the way a Viewer does. That is why “it looked fine when I opened it” is not a test. Use Modeling → View as (or Security → Test as role) with a user who only has Viewer (or app consumer) rights. Then repeat in the published app.

Static roles versus dynamic USERPRINCIPALNAME

Static roles hard-code a filter: [PlantId] = "CHI-01". They are honest, easy to test, and painful to maintain when you have forty plants. Use them for a handful of known audiences (internal control tower vs a single named customer) or during a pilot.

Dynamic roles use USERPRINCIPALNAME() (preferred in Microsoft 365) or USERNAME() against a bridge table: User email → PlantId, ClientId, or FacilityId. The bridge must match the identity string the service actually sends. DOMAIN\user versus user@tenant mismatches zero the filter and blank the report. Store emails in lowercase, trim, and test both a cloud-only account and a synced AD account if you have hybrid identity.

Do not use USERNAME() in a tenant where UPN is the contract. Document which function the role uses next to the DAX. Change control: an RLS DAX edit is a security change, same review bar as a measure that moves margin.

Bridge table design that does not explode

Keep the entitlement table thin: UPN, the security key (PlantId / ClientId / FacilityId), and maybe a ValidTo date. Many-to-many between users and keys is normal. Relate entitlement[PlantId] to DimPlant[PlantId], then DimPlant to facts. Do not relate entitlement directly to a 200-million-row fact if a dimension can carry the key.

Users in two groups should see the union of rows, not the intersection, unless the business explicitly wants intersection (rare). Test a person in two plants and a person in none. The none case should be empty facts, not an error — and not a fallback to “show all” hidden in DAX.

Break-glass: a named compliance or IT role that is assigned in the service, not a FILTER(ALL()) pattern left in every role “just in case.” Admins who need to debug should View as, not disable RLS in production.

Map Entra groups in the service

Roles live in the dataset. Group assignment lives in the Power BI / Fabric service (dataset security pane) or, for some embed patterns, in the effective identity you pass. Publishing a PBIX does not copy who is in the role. After first publish, assign Entra security groups to roles. Nested groups work if the token expands them; test rather than assume. Mail-enabled distribution lists are a common miss.

App audiences control which people install which app. They do not replace RLS. A user in the app who is not in an RLS role (and has no other bypass) should not see the restricted facts. Test that combination explicitly: in the app, as that user.

Import, DirectQuery, and Dual

Import applies RLS in VertiPaq when the query runs. DirectQuery must push predicates to the source. If the RLS filter does not fold, you either fail, scan too much, or (worse) designers add bidirectional spaghetti to “make it work.” For healthcare and large TMS warehouses, prove folding with View Native Query / Performance Analyzer before you promise department-level security on DirectQuery.

OLS (object-level security) hides tables or columns. It is not a substitute for row filters. Combining OLS and RLS is possible and easy to get wrong; ship RLS first unless a column is literally prohibited (for example a raw identifier you cannot show to a vendor).

Embed and “app owns data”

Embed for your organization still uses Entra users; test with real accounts. Embed for your customers (app owns data) requires Effective Identity with roles (and custom data if you use username mapping). Empty visuals after embed are often identity bugs: role name mismatch, missing role in the token, or RLS DAX that references USERPRINCIPALNAME() when the embed identity is a custom string. Log the identity you send. Do not debug by turning RLS off in the customer tenant.

The test matrix before go-live

  • Persona A: single key (one plant, one shipper, one unit). Fact counts match a SQL query with that filter.
  • Persona B: two keys. Union of rows; totals are not double-counted across a many-to-many.
  • Persona C: no keys. Empty facts, dimensions may still show (decide whether to filter dimensions too).
  • Persona D: executive / control tower role that should see the network — assigned on purpose, not because they are Admin.
  • Repeat in Desktop View as, in the workspace as Viewer, and in the app. If embed is in scope, repeat with a token.

Bidirectional relationships can walk around a role filter. Prefer single-direction stars. If a bidirectional is required for a slicer, add it to the test matrix and write why it cannot leak. Filtering the wrong table (a disconnected security table) is still the most common leak we see in reviews.

Industry patterns

Logistics / 3PL: ClientId or AccountId on the shipment spine. Internal dispatchers get a control-tower role. Embedded customer portals must pass Effective Identity roles; blank pages are usually the token, not the gateway.

Healthcare: FacilityId, service line, or unit. PHI-minded RLS plus a ban on Publish to web. Dynamic UPN against a staff-to-unit bridge, tested for nursing, coding, and a break-glass compliance admin. Need-to-know is the product, not a policy appendix.

Manufacturing: PlantId or LineId. Corporate controllers roll up; plant managers do not. Test a plant manager, a quality lead, and a corporate role. Do not validate only while Workspace Admin.

Joiner, leaver, and org-restructure process

RLS that depends on editing the PBIX when someone joins is not RLS; it is a ticket queue. Entitlement should follow Entra group membership. When a plant is sold or a 3PL customer offboards, the bridge table and the group both need an owner. Put ValidTo on the bridge if you cannot remove rows the same day. Retest View as after every org restructure — not at the next annual access review.

Document the break-glass path: who can View as, who can assign groups, who is the dataset steward. If that is one consultant’s personal account, you do not have a production security model.

Performance Analyzer and RLS

A role filter that looks cheap in Desktop can explode when it walks a bidirectional path on a large fact. Capture Performance Analyzer under View as for the heaviest persona, not only as Admin. If DirectQuery, confirm the RLS predicate appears in the native query. If it does not, you are scanning too much or the source cannot enforce the filter — either way, do not ship.

Calculated tables that materialize unfiltered copies of facts will ignore RLS in ways authors do not expect. Prefer relationships and role filters on dimensions. If you must use a calculated table, include it in the leak test: does Persona A see Persona B’s keys in that table?

A worked 3PL example

FactShipment[ClientId] relates to DimClient[ClientId]. Entitlement is UPN × ClientId. Role “Shipper” filters Entitlement[UPN] = USERPRINCIPALNAME(). Role “ControlTower” is a static filter that includes all ClientId values used internally — assigned only to an Entra group IT controls. A shipper user in two ClientId rows sees the union. A user with no entitlement rows sees empty facts. Embed for a customer portal sends Effective Identity with role Shipper and a username that matches the bridge. If the portal shows blank, log the username in the token before rewriting DAX.

RLS does not encrypt data at rest. It does not replace sensitivity labels, workspace separation for HR/finance, or a decision that some datasets should not exist. It does not fix a model whose keys cannot be conformed. If ShipmentId is not stable, no role expression will save a 3PL portal.

For the symptom-first version (blank report, leaked region, Desktop vs service), use the RLS troubleshooting guide. For ownership, endorsement, and unofficial reports, use Power BI governance. Industry context: logistics, healthcare, manufacturing.

row-level-securitygovernancePower BI

Apply this insight in your organization

Power BI Analytics turns reporting guidance into a governed first release with clear owners, definitions, and adoption.

row-level-security

Illustrative KPI view

Sample model

Revenue

$4.2M

+9.4% vs LY

Gross margin

30.5%

+0.6 pts

Decision cycle time

3.4 days

+0.3 days

Open exceptions

9

+5 vs last week

Trailing 12 periodsvs plan
On track
79%
Watch
26%
Critical
6%

Related Power BI topics

Move from this article into services, industries, audits, and proof points on the same subject.

Response within one business dayClear first-release scopeGoverned KPI definitionsSecurity-aware delivery

Ready to improve your reporting?

Book a free consultation to discuss your Power BI priorities, data landscape, and a practical first release.