Skip to content

Runtime Permissions

Sam Betts edited this page Nov 5, 2026 · 7 revisions

Prerequisites → Runtime Permissions

Microsoft 365 runtime service principal

The runtime account needs two kinds of access, both described below:

  1. Microsoft Graph & Microsoft 365 API permissions — to read Microsoft 365 data (consented by an Azure AD administrator).
  2. Azure RBAC roles — data-plane access to the Azure resources the solution deploys (assigned automatically by the installer).

Note: the solution can run without some of the API permissions if an incomplete dataset is acceptable. Where access isn't granted, it logs an error and continues working.

Microsoft Graph & Microsoft 365 API permissions (application)

Important: without an Azure AD administrator's consent, these permissions will not be active.

API Permission Reason
Graph AppCatalog.Read.All Not used by current builds: nothing in the code reads the Teams app catalog. The Teams import reads each channel's tabs, including the Teams app behind each tab, with Group.Read.All, which Microsoft documents as sufficient for listing a channel's tabs, and the installer's checks don't ask for this permission. Don't grant it for a new installation. If an existing one holds it, run a Teams import without it in a test tenant before you revoke it.
Graph CallRecords.Read.All Reading call-record data after calls are made.
Graph CopilotPackages.Read.All (Optional.) Reading the Microsoft Agent 365 Package Management API catalog. Required only when Agent365PackageCatalog is enabled. Requires a Microsoft Agent 365 license, admin consent, and the global cloud. See Agent 365 package catalog.
Graph Group.Read.All Enumerating Teams data and reading direct members of UserGroupsFilter groups; both WebJobs need it when that filter is used. Also covers the optional leadership group. GroupMember.Read.All suffices for leadership membership alone, not all group reads. See import scoping.
Graph OnlineMeetings.Read.All Reading Copilot event meeting context. Also needs a Teams application access policy — see Copilot → Meeting enrichment also needs a Teams application access policy.
Graph Organization.Read.All Reading SKUs for users at an org level.
Graph Reports.Read.All Reading user and device usage reports, and the three Microsoft 365 Copilot usage reports when GraphCopilotUsageReports is enabled. Global cloud only. A missing or unconsented grant now fails the report import rather than recording an empty day — see Copilot usage reports.
Graph Sites.Read.All Reading SharePoint file metadata for Copilot file events (via /sites/{id}/lists/{listId}/items).
Graph AiEnterpriseInteraction.Read.All (Optional, and not granted by the installer.) Reading Microsoft 365 Copilot AI interaction history, i.e. prompt history. Required only when CopilotInteractionHistory is enabled. This one needs explicit admin consent — see Copilot AI interaction history needs its own consent below.
Graph AuditLogsQuery.Read.All (Optional, and not granted by the installer.) Searching the Microsoft 365 unified audit log for Copilot interactions older than the live import can reach. Required only to run a Copilot audit backfill (Preview). Needs explicit admin consent. It can read the whole audit log, so you can remove it again once you no longer need the backfill.
Graph Mail.Read (Optional) Reading the message properties of each in-scope user's Sent Items for the Sent Email Import feature. Required only when SentEmails is enabled in ImportJobSettings. Application Mail.Read can read every mailbox in the tenant, and UserGroupsFilter limits what is processed, not what the app can access. Restrict which mailboxes it can read in Exchange Online: either keep this consent and constrain it with an application access policy, or remove the consent and grant a scoped RBAC for Applications role assignment instead, which Microsoft describes as the replacement for application access policies. An RBAC assignment adds to an Entra consent rather than restricting it, so don't keep both. Test Configuration checks for the Entra consent, so it reports an error on the RBAC-only route; verify the import yourself. Either way, test both an allowed and a denied mailbox. The import scans the mailboxes of users the user import has stored, so it also needs User Entra ID extended metadata (GraphUsersMetadata). See Sent Email Import.
Graph User.Read.All Resolving user IDs to email addresses. Required for various processes.
Office 365 Management ActivityFeed.Read Reading audit data for SharePoint Online events, and for Power Platform adoption events (Power Apps, Power Automate, Power BI, Copilot Studio — read from both the legacy PowerApps/MicrosoftFlow workloads and the unified PowerPlatform admin activity feed). See Power Platform auditing prerequisites below — the events will not flow unless Power Platform auditing is enabled per environment.
Office 365 Management ActivityFeed.ReadDlp (Optional, and not granted by the installer.) Reading Data Loss Prevention policy events (the DLP.All feed). Required only when ImportDlp is enabled. This is a separate grant from ActivityFeed.Read with its own admin consent. You do not need it for Copilot DLP reporting — see Data Loss Prevention import is optional, and is not what powers Copilot DLP reporting below.
Application Insights API Data.Read Reading Application Insights data. Only needed for web-traffic imports.

Directory.Read.All and Test Configuration. Current builds' Test Configuration reports an error if the runtime app doesn't hold Directory.Read.All while the user metadata import (GraphUsersMetadata) is on, and the installer's Prerequisites report says the user import "reads other users' directory memberships". That describes an older per-user memberOf read. The current import doesn't use the permission: it reads people with User.Read.All and, only when UserGroupsFilter is set, the groups' direct members with Group.Read.All. Whether to grant the broader permission just to clear that one test result is your decision.

If the runtime app can't read the UserGroupsFilter groups, the imports fail open: they keep the membership they last resolved, or import everyone if none has been resolved since the WebJob started. See Security model → Data privacy.

No longer required: TeamsAppInstallation.ReadForUser.All. It existed for per-user Teams app-install tracking, which was removed in Stable build 1807. If it is still granted you can revoke it; nothing reads it any more. See Data Collection → Per-user Teams apps tracking (removed).

Copilot AI interaction history needs its own consent

The CopilotInteractionHistory import is deliberately harder to turn on than the others, and there are three separate prerequisites — all of them must be in place or the import does nothing:

  1. AiEnterpriseInteraction.Read.All, admin-consented. The installer does not request or grant this permission. An Entra administrator has to add it to the runtime app registration and grant admin consent explicitly. Without it the import fails rather than silently recording an empty run.
  2. The M365_COPILOT_BUSINESS_CHAT service plan on each user. Users without it return nothing.
  3. A scope, in practice. The Graph endpoint (/copilot/users/{id}/interactionHistory/getAllEnterpriseInteractions) is one HTTP call per user. At the ~200,000-user design target an unscoped run would mean 200,000 Graph calls per import cycle. Point it at a pilot group with UserGroupsFilter; the import is also capped per cycle as a backstop.

Privacy — read before enabling. The importer never stores prompt or response text; it stores derived statistics (word counts, attachment counts, response latency and similar). However, if Cognitive Services is also configured, prompt text is sent to Azure AI Language so that language, sentiment and keywords can be extracted and stored. Extracted keywords can amount to a whole short prompt. That is a new egress path for prompt content out of your tenant and should be a conscious, documented decision — see Security Model → Copilot prompt content.

(Optional) If you need to access Yammer data, the setup needed is explained in /export · Yammer Developer Site.

Data Loss Prevention import is optional, and is not what powers Copilot DLP reporting

The ImportDlp toggle and its ActivityFeed.ReadDlp permission are entirely optional. The solution installs, runs and reports perfectly well without them, and the installer neither requests nor grants the permission.

The single most important point: the "DLP impact on Copilot" report — which agents and people are being blocked, and by which policies — does not need this permission or this toggle. That data arrives on the Copilot interaction records you are already importing under Copilot.

Why: DLP policies scoped to the "Microsoft 365 Copilot and Copilot Chat" location do not emit records on the DLP.All feed at all. Microsoft documents that feed's workloads as Exchange Online, Endpoint and SharePoint/OneDrive only. A Copilot block is instead reported inside the CopilotInteraction record, on AccessedResources[].Status and AccessedResources[].PolicyDetails, next to AgentId / AgentName — which is also the only reason per-agent attribution is possible at all. See Audit logs for Copilot and AI applications.

So the two DLP sources answer different questions:

Needs ActivityFeed.ReadDlp? Enabled by Answers
Copilot-embedded DLP No Copilot (already on for Copilot reporting) Which agents and people were blocked, and by which policies
DLP.All feed Yes ImportDlp Tenant-wide policy activity across Exchange, SharePoint/OneDrive and endpoint devices

Turn ImportDlp on only if you want that second, tenant-wide picture. Note it can never be attributed to a Copilot agent: DLP records carry the literal UserKey = "DlpAgent" and no agent identity, so the report shows them in their own section and deliberately does not join them to Copilot activity.

If you enable it without the permission, nothing else breaks. The DLP subscription is treated as optional: the importer logs a warning naming the missing grant, drops that one feed for the cycle, and every other workload imports normally. Once an administrator consents, DLP data starts arriving on the next cycle with no reinstall.

Privacy: the solution deliberately does not request the separate "Read DLP policy events including sensitive details" permission. It records that a policy fired — the policy, rule, severity and action — and never the content that triggered it.

Power Platform auditing must be turned on

The ActivityFeed.Read permission lets the importer read Power Platform audit events from the Office 365 Management Activity API, but those events only exist if Power Platform auditing is enabled in the tenant. No Power Platform adoption data will appear in reports until a Power Platform / global admin completes the steps below.

  1. Confirm Microsoft Purview Audit is enabled at the tenant level. Usually on by default, but a tenant admin can verify (and turn it on if necessary) from the Microsoft Purview portal. See Microsoft Purview auditing solutions overview. This single setting is enough for Power BI / Fabric activity events to flow — there is no separate Power BI tenant toggle to enable.
  2. Configure and turn on auditing for each Power Platform production environment you want to monitor (applies to Power Apps, Power Automate, Copilot Studio and Dataverse). This is the step that's most often missed — adoption events for those workloads only flow for environments where auditing has been explicitly turned on. See Overview of Power Platform activity logging and auditing in Microsoft Purview → Configure and turn on auditing for each Power Platform environment.

Per-workload Microsoft Learn references the importer is built against:

Workload Microsoft Learn
Power Apps View Power Apps activity logs in Microsoft Purview
Power Automate View Power Automate activity logs in Microsoft Purview
Power BI Track user activities in Power BI (no separate tenant toggle — uses the Purview audit log)
Copilot Studio Audit Copilot Studio activities in Microsoft Purview
Power Platform admin (unified) Power Platform Administrator Activity (RecordType 256)

If reports show empty Power Platform tables after deploy, the most likely cause is that auditing is on for the tenant but not for the target Power Apps / Automate / Copilot Studio environment(s). Validate by searching the Microsoft Purview portal audit log for the corresponding activity (e.g. LaunchPowerApp, FlowRunStarted, ViewReport) before suspecting the importer.

Delegated permissions (optional)

Teams delegated permissions apply only to deep Teams analytics and are requested through Connect to Microsoft Teams, not ordinary sign-in. The billing connection is a separate optional delegated Power Platform flow. Choose Delegated, not similarly named application permissions.

Older builds asked for these at every sign-in. Before Stable build 1846, a runtime app registration without consent for them stopped anyone signing in, with AADSTS65001. See Known Issues.

API Permission Reason
Graph ChannelMessage.Read.All Reading channel messages in the Teams an administrator authorises for deep analytics (see Enable Deep Analytics for Teams). Always needs admin consent.
Graph Team.ReadBasic.All Listing the administrator's own Teams on the Teams permissions page.
Power Platform API CopilotStudio.Licenses.Read; EnvironmentManagement.Environments.Read Consumption connection only. Add/grant delegated consent on the runtime registration, use the same authorised administrator, register the exact Web /signin-agent-costs callback and provide durable Storage/Table access. See Agent costs setup.

Azure RBAC roles (data-plane)

Beyond the API permissions above, the runtime service principal needs data-plane access to the Azure resources the solution deploys (so it can read/write storage, call Azure AI Language, and send/receive Teams-call messages). The installer assigns these Azure RBAC roles automatically when you install or re-run it. Since Stable 1859 (PR #828) it assigns each data-plane role on the one resource the runtime uses, and only Reader on the resource group, which can hold other workloads; earlier installers assigned every role on the resource group. They are listed here so you can pre-grant, audit, or assign them manually (for example for a binaries-only redeploy, or where policy restricts who may create role assignments).

Azure RBAC role Scope Why When
Reader Resource group Read resource metadata, including Application Insights. Always
Storage Blob Data Contributor The solution's storage account (the resource group before 1859) Create containers and read/write blobs. Always
Storage Table Data Contributor The solution's storage account (the resource group before 1859) Read/write the AnalyticsState table for runtime state and table-based checkpoints when shared-key storage access is disabled. Always
Cognitive Services User The Azure AI Language account (the resource group before 1859) Data-plane calls to Azure AI Language (sentiment / key-phrase) when key auth is disabled. If Cognitive Services is enabled
Cognitive Services OpenAI User The Azure OpenAI account (the resource group before 1859) Inference for the optional prompt-categorisation backend's runtime Entra credential, not permission to send prompts Installer-managed Foundry service enabled; assign manually for an approved existing deployment
Azure Service Bus Data Owner The Teams calls queue, graphcalls (the resource group before 1859) Send (calls webhook) and receive (importer) on the Teams-calls queue via Entra ID RBAC instead of a SAS key. Since Stable 1856 (PR #768): the importer also sends, to re-queue a failed call for a later retry, which this role already allows. If Service Bus (Teams calls) is enabled

Service Bus: if your namespace has local (SAS) authentication disabled, the importer authenticates with Entra ID RBAC and requires the Azure Service Bus Data Owner role above. Re-running the installer assigns it; for a binaries-only redeploy, assign it once manually or the calls processor will return 401 Unauthorized.

Upgrading from a build before 1859: a re-run adds the resource-scoped assignments, but doesn't remove the older ones on the resource group, because nothing records whether the installer or an administrator made them. Each run logs a warning for each one it finds, with the az role assignment delete --ids <assignment-id> command that removes it. Once the solution has run normally on the narrower assignments, remove them with that command, or in the resource group's Access control (IAM). Role changes can take a few minutes to apply.

Key Vault: the runtime app and the App Service's managed identity can read the runtime secret and certificate. The installer grants this with a vault access policy (runtime app: secrets Get/List and certificates Get; managed identity: secrets Get and certificates Get) or, on a vault that uses the Azure RBAC permission model, with Key Vault Secrets User and Key Vault Certificate User at vault scope. The installer's own app gets permission to write the secret: Key Vault Secrets Officer on an RBAC-model vault. The installer adds all of this automatically; see Security model → Secrets & Key Vault.

The optional agent-cost imports need two grants the installer deliberately does NOT make. Both are tenant-wide or subscription-wide privilege grants, so they are left to an administrator who can make that decision:

Import Grant needed Scope Who can grant it
Copilot Studio capacity Power Platform Reader for the runtime enterprise application Tenant Power Platform Administrator
Copilot Studio consumption Delegated Power Platform consent and connected administrator with billing access; no app-only fallback Shared deployment connection Entra consent administrator and authorised billing/portal administrator
Azure costs (AzureCostManagement) Cost Management Reader Every scope you want to read Owner / User Access Administrator on that scope, or a billing admin for EA/MCA

The Azure import additionally does nothing until you set the AzureCostScopes app setting — it has no default. Without these, ticking the boxes produces authorization failures or an empty report rather than data. Full setup: Agent costs.


Return to Prerequisites · All topics in this guide

Start here

Copilot analytics

Using the portal

Install & configure

Beyond Copilot

Operate

Upgrading from an older build

Reference

Project

Clone this wiki locally