Microsoft 365: setting up CloudHiro access
This guide is for you, the customer — a user with Global Administrator or Privileged Role Administrator access in your Microsoft 365 tenant. CloudHiro needs an app registration with read-only Graph API permissions.
What we're asking you to create
An app registration in Microsoft Entra ID (formerly Azure AD), with read-only, application-level Microsoft Graph permissions that you explicitly approve.
Steps
Use the Costi App Registration and do the following:
1. Add the permissions for your reports
Go to API permissions → Add a permission → Microsoft Graph → Application permissions, and add the following, based on which reports you want CloudHiro to collect.
Why we're asking for each one — every permission below is read-only, and each maps to a specific cost-optimization question CloudHiro answers for you:
| If you want CloudHiro to collect… | Grant these Application permissions | What this lets us read | The recommendation it enables |
|---|---|---|---|
| License/seat inventory | LicenseAssignment.Read.All (or Directory.Read.All), User.Read.All, Group.Read.All | Your purchased SKUs, seat counts, and who (or which group) each license is assigned to | Find unassigned/unused seats you're paying for, and attribute license cost to departments via group-based assignment |
| User directory, domains, admin units | User.Read.All, Organization.Read.All, Domain.Read.All, AdministrativeUnit.Read.All | Basic user directory metadata (name, department, job title, enabled/disabled status) and your tenant's org structure — not email, files, or chat content | Cross-reference disabled/stale accounts against license data (a disabled account with an active license is pure waste), and roll cost up by department/org unit |
| Usage reports (Exchange, Teams, SharePoint, OneDrive, M365 Apps, Viva Engage) | Reports.Read.All | Per-user activity counts for each product over a rolling window (e.g. last mailbox sign-in, Teams messages sent) — activity counts only, never message/file content | Identify users licensed for a product they never actually use, the same "paying for an idle seat" signal across every core M365 workload |
| Microsoft 365 Copilot per-user usage | Reports.Read.All (same permission as the usage reports row above) | Per-user Copilot activity (whether and how often each licensed user actually used Copilot) | Copilot is an expensive per-user add-on — a licensed user with zero Copilot activity is a directly reclaimable seat, the sharpest per-seat cost signal in the base Graph API |
| Teams Phone / Calling Plans call records (optional — only if you use Teams Phone and want call-volume reporting) | CallRecords.Read.All | Call metadata (participants, duration, timing) for your organization's Teams Phone/Calling Plans usage | Right-size Calling Plan/Teams Phone license counts against actual call volume — this is operational usage context, not itself a specific idle-seat flag |
| Intune managed-device inventory | DeviceManagementManagedDevices.Read.All | Device inventory: OS, compliance state, ownership type, enrollment/check-in metadata | Surfaces the device fleet CloudHiro can later cross-reference against license/activity data to flag stale or abandoned managed devices |
| Defender security posture (secure score, alerts) | SecurityEvents.Read.All | Your Defender secure score control profiles (which security controls are available vs. actually configured) and alert volume | Flags paid Defender-tier features (e.g. Safe Links, Safe Attachments, specific Conditional Access policies) that your license already covers but your tenant isn't configured to use — you're paying for capability you aren't using |
| Dynamics 365 app assignments | Application.Read.All | Which users/groups are assigned to each Dynamics 365 app | Find Dynamics 365 apps with many assigned seats but that data suggests are underused — the same idle-seat pattern as the license-inventory row, applied to Dynamics |
| Windows 365 Cloud PC inventory | CloudPC.Read.All | Cloud PC inventory (status, size tier, last-modified time) and utilization (actual connected hours, last-active time over the trailing four weeks) | This is the sharpest signal in the whole integration: a Cloud PC is a per-seat virtual machine billed monthly the moment it's provisioned, whether or not anyone connects to it — we flag provisioned-but-idle Cloud PCs using real usage hours, not just staleness |
| Entra ID Governance (PIM, Access Reviews) | RoleManagement.Read.Directory | Your PIM role-assignment and Access Review configuration | PIM/Access Reviews are Entra ID P2 premium features — near-zero usage here, combined with the license data showing you're on the P2 tier, means you're paying for a premium capability you aren't actually using |
You only need to grant permissions for the reports you actually want; skip a row entirely if that data isn't relevant to you.
Teams call records note: Grant CallRecords.Read.All only if you use Teams Phone and want call-volume reporting. This includes call metadata such as participants, duration, and timing. It provides operational usage context, not itself a specific idle-seat flag.
2. Grant admin consent
Click Grant admin consent for <your organization> — this is the step that actually activates the permissions; adding them alone isn't enough.
Additional step: enabling Power Automate or Dataverse reporting
If you also want CloudHiro to report on Power Automate (environments, connectors, and flow run history) or Dataverse capacity consumption, additional Power Platform authorization is needed beyond the Graph grants above. Power Automate flow history also needs separate environment access.
Why we're asking for this: this reads your Power Platform environment/connector inventory, flow run history, and Dataverse per-environment storage/capacity consumption. This provides evidence for reviewing connector licensing and Dataverse storage demand. Capacity consumption alone is not your invoice or proof of an automatic overage charge, and it does not include a guaranteed purchased-capacity comparison.
- Use the same app registration and secret or certificate. Follow Microsoft's Power Platform authentication setup for Power Platform API, app ID
8578e004-a5c6-46e7-913e-12f58912df43. Its delegated permissions do not authorize CloudHiro's app-only collector; authorization comes from the role assignment in the next step. - Have a Power Platform Administrator or Power Platform role-based access control administrator assign Power Platform reader to your app's service principal, using Microsoft's role assignment tutorial. The reader role ID is
c886ad2e-27f7-4874-8381-5849b8d8a090; use this in place of the tutorial's Contributor role. Use the app's Enterprise application Object ID and the documented tenant scope/tenants/<your tenant ID>. Send CloudHiro the Object ID and assigned scope so they can check the setup. This RBAC feature is currently preview. - Only for Power Automate flow history: in each target Dataverse environment, create an application user for this app under Settings → Users + permissions → Application users. Give it a security role limited to reading the workflow metadata CloudHiro uses to discover flows (IDs and names). Agree and validate the required read privileges with your CloudHiro contact; System Administrator access is not needed for this reporting. This step is separate from capacity reporting and Power Platform RBAC.
- Before enabling Dataverse capacity reports, CloudHiro must validate the capacity endpoint, permissions, returned fields, units, and database/file/log categories against your tenant. These are implemented but not yet confirmed against a live tenant. A successful connection or environment-list check alone does not confirm capacity reporting works.
Skip this section entirely if you don't use Power Automate/Dataverse or don't want this reporting.
What CloudHiro can and cannot do with this access
Can: read license assignments, user directory metadata, usage activity reports, Cloud PC inventory/utilization, Intune device inventory, Defender secure score, Dynamics 365 app assignments, PIM/Access Review configuration, and (only if you granted it) Teams call metadata, Power Automate environment/connector and flow-run metadata, or Dataverse storage-capacity data within the scope above.
Cannot: read email content, file/document contents, chat message content, export Dataverse business-table records, or modify any user, license, device, or tenant setting. This is a read-only reporting integration. Flow-history discovery reads Dataverse workflow IDs/names, which are configuration metadata rather than business-table exports.
Questions?
Contact your CloudHiro representative — they can walk through this setup live if you'd prefer not to do it solo.