Part 1: Microsoft 365 Data Ingestion
Set up a Microsoft 365 app so ConfigView can pull your Microsoft 365 data into the dashboard.Step 1: Create an App or Token
This setup explains how to register and configure an application in Microsoft Entra ID (Azure AD).- Retrieve your Tenant ID.
- Create a new App Registration in Azure AD for ConfigView.
- Create a Client Secret for the application and copy its value.
- Assign the required Read-Only permissions for Microsoft Graph APIs and Microsoft 365 data (Users, Groups).
- Grant admin consent for the selected permissions.
Step 2: Add the Token to ConfigView
-
Go to your ConfigView dashboard:
https://{companyname}.configview.com/admin/integrations/microsoft-365 -
Under Credentials, enter each value and click the save icon on its row:
MSFT_CLIENT_SECRET_VALUE holds the client secret value, not the secret’s ID.
Azure shows both on the same screen and only displays the value once — copy the
Value column, not Secret ID.
Step 2b: A second Microsoft tenant (optional)
If you have two Microsoft tenants, the Microsoft 365 - 2 app collects the second one into parallel_2 tables (msft_users_2, msft_managed_devices_2, …). It needs its own
app registration in the second tenant, and its own secrets:
Graph permissions are granted per app registration, not per organisation. Every
permission in the tables below has to be added and admin-consented separately on the
second app registration. A tenant that works for one script family and 403s for another
is almost always a permission granted on only one of the two registrations.
Which tenant is “1” and which is “2” is just the order they were configured — there is
nothing inherently primary about the unsuffixed one. If your production tenant is
configured as the second one, the reports that matter are the
_2 variants
(microsoft2.* seeds and coverage.msft2_*), and the unsuffixed reports will describe
the other tenant. Worth confirming which is which before acting on a Microsoft report.
Step 3: Enable the Microsoft 365 App in ConfigView
- Go to:
https://{companyname}.configview.com/admin/integrations/microsoft-365 - Click Connect. ConfigView creates its tables and schedules every collector at your default run time.
- Click Verify now to confirm the credentials work.
Step 4: Verify
- Go to:
https://{companyname}.configview.com/admin/status/ - Run the Microsoft 365 health check.
- All checks should pass.
Required Microsoft Graph Permissions
All permissions below are Application (app-only) permissions, used with the client credentials flow. After adding any permission, click Grant admin consent in the Azure portal. Only add the permissions for the scripts you intend to enable. Some endpoints additionally require an Entra ID P2 license (noted below).Core identity & inventory
Tenant settings & policy
Admin consent requests
microsoft_get_consent_requests collects the same list the Entra portal shows under
Enterprise applications → Admin consent requests — which app was requested, by whom,
their written justification, the approve/deny verdict and who reviewed it. It is request
history, not just what is pending: Completed and Expired requests going back years are
returned alongside InProgress ones.
ConsentRequest.Read.All is the least-privileged permission for these two endpoints and
is what we recommend granting. It is not the only one that works: a tenant whose app
registration already holds the much broader Directory.Read.All can read both endpoints
without adding anything — verified on both Thrive tenants 2026-09-18, where the
collectors return data on Directory.Read.All alone. If you are choosing, prefer
ConsentRequest.Read.All.microsoft_get_admin_consent_request_policy collects the workflow’s own configuration,
and is the reason an empty request list is readable. If isEnabled is 0 the admin
consent workflow is switched off in that tenant and an empty
msft_consent_requests is the correct answer rather than a collection failure. Check that
column before investigating an empty table.
These two collectors are paced more tightly than the rest of the folder. The
identityGovernance endpoints throttle on a burst window — roughly 23 requests per
10 seconds, measured — and each consent request needs its own follow-up call for the
requester and verdict. A tenant with a few dozen requests takes under a minute.Roles & PIM
Licenses & billing
Microsoft does not expose full invoice/payment billing through Graph. For invoices and usage charges, use the Microsoft 365 admin center or Partner Center APIs.
Mailboxes & calendars
microsoft_get_calendars reads the calendar list for each mailbox — one row per
calendar, with its name, owner, and sharing flags. It does not read events, so no
meeting subjects, bodies, or attendee lists enter your database.
Calendars.ReadBasic is enough to collect it. Granting Calendars.Read as well
fills in three columns that ReadBasic withholds — canEdit,
canViewPrivateItems, and changeKey — which stay NULL under ReadBasic
rather than defaulting to false. Note that Calendars.Read is the permission
whose portal description reads “Read calendars in all mailboxes”; there is no
permission literally named Calendars.ReadAll.
Both are Application permissions and both grant tenant-wide mailbox access. To
narrow that, scope the app registration with an application access
policy so it
can only reach a chosen mail-enabled security group. Mailboxes outside the policy
return 403 and are skipped without failing the run.
OneDrive / SharePoint / external sharing
Audit & sign-ins
Security & identity protection
Teams & communications
Intune device policies
After granting any new permissions in Azure AD, restart the satellite (or wait for the next cron run) — tokens are cached per script invocation and will pick up the new scopes on the next run.
Device inventory: which table joins to other systems
Device.Read.All and DeviceManagementManagedDevices.Read.All return different things,
and only one of them is useful for cross-system device reporting:
So
msft_managed_devices is the only Microsoft table that can be joined to an MDM or EDR
inventory by serial. If you want reports like “Intune devices with no CrowdStrike agent”
(coverage.msft_missing_crowdstrike), you need the Intune permission — Device.Read.All
alone will not do it. Matching msft_devices.displayName against an EDR hostname instead
is not a workable substitute; measured against a real tenant it matched under 20% of
devices.
Troubleshooting an empty msft_managed_devices
An empty Intune table has two very different causes, and the collector’s own output
distinguishes them:
Fetched 0 devicesand the run succeeds — the permission is fine and the tenant genuinely has no Intune-enrolled devices. Common on tenants that use a different MDM (Jamf, Kandji, Workspace ONE) or on a sandbox tenant. Nothing to fix.403 Client Error: Forbiddenon/deviceManagement/managedDevices— the app registration is missingDeviceManagementManagedDevices.Read.All, or it was added without clicking Grant admin consent. NoteDevice.Read.Alldoes not cover this endpoint; an app can hold it and still 403 here.
roles claim of an
app-only token — it lists exactly the application permissions that were consented:
Directory discovery
microsoft_get_directories builds an inventory of the Entra directories around your
tenant — their names, default domains and identity providers — into msft_directories.
It resolves each one through Microsoft Graph’s cross-tenant lookup, which answers for any
directory without consent in it, so a directory appears here whether or not ConfigView
collects it.
It finds candidates three ways: the guest accounts in your own tenant (the directories
your guests come from), the homeTenantId on cross-tenant sign-ins, and a list you
supply. The list matters because no app-only credential can enumerate directories — the
Azure portal’s Directories + subscriptions switcher is a view of the signed-in
person’s memberships, not something an API exposes. A certificate or sandbox tenant that
has never invited a guest and never had a sign-in is invisible until you name it.
Set the optional secret MSFT_KNOWN_DIRECTORIES (and MSFT_KNOWN_DIRECTORIES_2 for the
second tenant) to a comma-separated list of tenant IDs or domains, copied from that portal
page:
discovered_via, so a row
that exists only because you seeded it is distinguishable from one your own data found.
The payload is a directory’s public identity only — never its users, subscriptions or
resources, which still require an app registration and role assignment inside it.
Data Tables
Once the scripts run, the corresponding Microsoft 365 tables will be created in your database. All tables include arun_at column for historical tracking.