Skip to main content

Granting Power BI workspace access

ReportMesh embeds Power BI reports using its own identity, not the identity of the person looking at them. Power BI never sees your end users. This page covers giving that identity access to the workspaces holding the reports you intend to register.

Who this is for: A Fabric administrator, for the tenant settings, and a workspace administrator, for workspace membership. These are often two different people, and the tenant settings cannot be delegated to a workspace administrator.

Prerequisite: The content registration from Setting up Entra ID. You need its Application (client) ID and its display name before starting.

How Power BI actually grants this​

Worth stating before the steps, because it catches people out.

Power BI ignores Entra API permissions for this. Adding Power BI permissions to the app registration does nothing at best, and produces errors that are hard to diagnose at worst. Microsoft recommends against it explicitly.

Access comes from three things instead, and all three must be true:

  1. A security group containing the identity.
  2. Tenant settings in the Fabric admin portal, enabled and scoped to that group.
  3. Workspace membership — the group added to each workspace holding content.

Miss any one and the failure is a 401 or 403 that does not say which one is missing.

Step 1 — Create a security group​

Scope the tenant settings to a group rather than enabling them for the whole organisation. It also means adding a second identity later is a membership change rather than a tenant-setting change.

  1. In the Entra admin centre, go to Identity → Groups → All groups → New group.
  2. Group type: Security. Not Microsoft 365 — Fabric tenant settings accept security groups.
  3. Group name: ReportMesh-ServicePrincipals.
  4. Membership type: Assigned.
  5. Under Members, add the content identity. Search by the app registration's name. You are adding the enterprise application object, which Entra created automatically alongside the registration.
  6. Create.
If it does not appear in the member picker

The enterprise application object may not exist yet. Open Identity → Applications → Enterprise applications and confirm it is listed; opening the app registration once usually brings it into being.

Group membership takes a few minutes to reach Fabric. If step 4 fails immediately after this, wait and retry before assuming something is misconfigured.

Step 2 — Enable the Fabric tenant settings​

  1. Open app.powerbi.com → Settings → Admin portal → Tenant settings. You need to be a Fabric administrator; the menu entry is simply absent otherwise.

  2. Under Developer settings, set both of these:

    SettingStateScope
    Service principals can call Fabric public APIsEnabledReportMesh-ServicePrincipals
    Embed content in appsEnabledReportMesh-ServicePrincipals

    For each: toggle to Enabled, choose Specific security groups, enter the group name, and Apply.

    Older tenants show the first as "Allow service principals to use Power BI APIs". Same setting, older name.

Both are needed. Enabling only the first gives API access without embed tokens, which fails later and less obviously.

Changes take up to 15 minutes

A 401 immediately after applying a tenant setting is usually just propagation. Wait before investigating.

Step 3 — Add the group to each workspace​

For every workspace whose reports will be registered:

  1. Open the workspace in app.powerbi.com.
  2. Workspace settings → Access → Add people or groups.
  3. Add the ReportMesh-ServicePrincipals group, not the identity individually. Adding the group means a future identity inherits access without revisiting every workspace.
  4. Assign the Member role.

Member, not Viewer or Contributor. Generating an embed token needs more than read access, and Viewer is not enough. Member is the lowest role that reliably supports this across report types, and it is what confers Build permission on the workspace's semantic models. Admin is more than is needed — do not use it.

Repeat for every workspace. A report in a workspace the group was never added to fails at embed time with a 403 naming neither the workspace nor the missing role.

Personal workspaces cannot be used

My Workspace does not support this kind of access at all. Content has to live in a proper workspace.

Step 4 — Verify before wiring anything up​

Confirm the identity works on its own, before configuring the application. Run these from any machine that can reach Power BI.

Acquire a token:

curl -s -X POST \
"https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
-d "grant_type=client_credentials" \
-d "client_id=<client-id>" \
-d "client_secret=<client-secret>" \
-d "scope=https://analysis.windows.net/powerbi/api/.default"

A token comes back whether or not steps 1 to 3 are correct. This only proves the credentials are valid.

List the workspaces it can see:

curl -s "https://api.powerbi.com/v1.0/myorg/groups" \
-H "Authorization: Bearer <token>"

An empty list means step 3 did not take: the identity is authenticated but a member of nothing. A 401 means step 2's tenant setting is missing, not scoped to the group, or has not propagated yet.

List reports in a workspace:

curl -s "https://api.powerbi.com/v1.0/myorg/groups/<workspace-id>/reports" \
-H "Authorization: Bearer <token>"

Generate an embed token — the call that actually proves the whole thing works:

curl -s -X POST \
"https://api.powerbi.com/v1.0/myorg/groups/<workspace-id>/reports/<report-id>/GenerateToken" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"accessLevel":"View"}'

A token in the response means Power BI access is configured correctly. A 403 here, when the two calls before it succeeded, points at Embed content in apps or a workspace role below Member.

If AI chat is in use​

AI chat runs queries against semantic models through the same identity, and needs two things beyond the above. Skip this entirely if AI chat is not deployed.

  1. A separate tenant setting. In Admin portal → Tenant settings, enable "Dataset Execute Queries REST API", shown in some tenants as "Semantic model execute queries REST API", scoped to the same group.

    This is not the same setting as "Service principals can call Fabric public APIs". Enabling one does not enable the other.

  2. Build permission on each semantic model to be queried. Workspace Member usually confers this, but it is granted per dataset — check it directly on the dataset under Semantic model → Manage permissions rather than assuming it from the workspace role.

Then smoke test it against a real dataset before relying on it:

curl -s -X POST \
"https://api.powerbi.com/v1.0/myorg/groups/<workspace-id>/datasets/<dataset-id>/executeQueries" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"queries":[{"query":"EVALUATE ROW(\"test\", 1)"}]}'

A 403 means either the tenant setting or the per-dataset Build permission is missing. The error does not distinguish them, so check both.

Row-level security​

Worth being explicit about, because this embedding model does not give it to you for free.

Power BI sees ReportMesh's identity, not the person viewing. Row-level security roles defined on a semantic model only apply where the embed token says who to treat the viewer as, so ReportMesh supplies that itself: each report carries a list of role names, each name is assigned to people and groups, and the roles the viewer holds are sent with the token.

Role names cannot be discovered from Power BI. The API reports whether a dataset enforces row-level security, never which roles it declares. Every name is typed into ReportMesh by hand and must match the model exactly; a name that does not match produces a token Power BI rejects.

Where a dataset enforces row-level security and the viewer holds no matching role, the report is refused rather than shown unfiltered. An administrator or publisher who has selected no role instead sees every role the report declares, which is the widest view the model allows.

What the token carries​

Every token for a report with row-level security carries the same two things, whatever the model's roles do with them. How Publishers register, assign, and check roles is in Row-level security.

FieldValue
rolesThe roles the viewer holds, directly and through their groups
usernameThe viewer's email as stored in ReportMesh, verbatim

A role with a fixed filter, such as [Country] = "France", ignores username. A role that compares a column against USERNAME() filters on it. Both work without any setting in ReportMesh, and a model can mix them.

Where a role compares against USERNAME(), the Power BI developer needs to:

  • Make the filter fail closed: an unrecognised value should match no rows, not every row. ReportMesh cannot detect a filter that defaults to TRUE().
  • Populate the model's user column with the same email addresses ReportMesh holds, including external guests, who have no Power BI identity of their own and are sent by their stored email.

Either way, hand over every role name the model declares.

ReportMesh sends the email without trimming or changing its case, because the model compares it character for character. An account whose email is blank, contains a space, or is longer than 256 characters is refused any report with row-level security, before any Power BI call.

An email the model does not contain produces an empty report, not an error. Nothing in ReportMesh or Power BI distinguishes that from a correctly empty slice. Publishers can preview the report as any of its viewers to check, but the preview shows the same empty page.

Row-level security also rules out AI chat on that report. Its queries run as the service principal, which cannot be scoped to a viewer's rows, so ReportMesh refuses them.

"Test as role" in Power BI Desktop proves nothing here

It uses the tester's own identity and does not reproduce how embedded reports authenticate. Verify with a real embed token, end to end.

Checklist​

  • The security group exists and contains the content identity.
  • Service principals can call Fabric public APIs — enabled, scoped to the group.
  • Embed content in apps — enabled, scoped to the group.
  • The group is a Member of every workspace holding content to be registered.
  • Listing workspaces returns the ones you expect.
  • Generating an embed token succeeds against a real report.
  • (AI chat only) Dataset Execute Queries REST API enabled and scoped to the group.
  • (AI chat only) A test query returns rows against a real dataset.
  • Where a model defines row-level security, its role names are registered on the report, assigned to at least one person, and verified with a real embed token.
  • Where a role compares against USERNAME(), a preview as one of the report's viewers shows that person's rows.

Common problems​

What you seeWhat it usually means
401 on any Power BI callThe step 2 tenant setting is missing, not scoped to the group, or has not propagated. Wait 15 minutes.
A token works, but no workspaces are listedStep 3 — the identity is in no workspace.
Reports list, but the embed token is refusedEmbed content in apps is disabled, or the workspace role is below Member.
The identity is missing from the group member pickerThe enterprise application object has not materialised. Open it under Enterprise applications.
One workspace works, another returns 403Step 3 was not repeated for that workspace.
A test query returns 403The AI chat tenant setting, or Build permission on that dataset.
Everyone sees every rowThe dataset declares no row-level security role, or the viewer is an administrator or publisher, who sees every declared role when none is selected.
A viewer is told no role has been assigned to themThe dataset enforces row-level security and that person holds no role on the report.
Embedding fails only for reports with row-level securityA registered role name does not match one the model declares.
A report opens empty for one personA role compares against USERNAME(), and their ReportMesh email is missing from the model's user column, or differs from it in spelling or case.
A viewer is told their email cannot be usedThe report has row-level security and that person's stored email is blank, contains a space, or is too long.
Sudden tenant-wide failure after months of workingThe client secret expired. Rotate it.

Next​

Granting SharePoint site access, for Excel workbooks.