Microsoft Intune — Integration Setup
Prerequisites
- A Microsoft Intune subscription with devices enrolled
- An Entra ID (Azure AD) account with Global Administrator or Privileged Role Administrator to grant admin consent
- CMDash Essentials tier or above
How this integration authenticates
Intune is read through Microsoft Graph using an Entra ID app registration with application permissions and the /.default scope — Microsoft's client-credentials idiom. CMDash holds an app-only token, never a person's.
A client-credentials grant has no refresh token by design. CMDash re-mints the token when it expires rather than attempting to refresh one that will never exist. If you have configured other Microsoft integrations (Defender, Sentinel, Entra ID), this is the same mechanism and the same app registration serves all of them.
Which directory is read depends on how the deployment runs its Microsoft integrations — see How CMDash connects to Microsoft:
- Per directory (CMDash SaaS): your administrator signs in and consents once, and the connection is bound to that directory. Available in the Commercial, GCC, GCC High and DoD clouds — Intune's
managedDevicesAPI is published in all three. See Connecting on CMDash SaaS below. - Single directory (self-hosted default): the deployment's own app registration and
AZURE_TENANT_ID. Steps 1–4 below.
Connecting on CMDash SaaS (per directory)
Available once CMDash's Microsoft apps are registered. Until then Connect answers that the Microsoft app registration is not set up on this deployment.
- Integrations → Microsoft Intune → Connect, and choose your Microsoft cloud.
- Sign in as an active Global Administrator or Privileged Role Administrator and accept the permissions for your organisation. CMDash's app asks for
DeviceManagementManagedDevices.Read.All(read-only; the consent screen also lists the permissions of CMDash's other Microsoft integrations — one consent covers all of them). - You are returned to CMDash; the connection is bound to your directory and runs its first health check. The integration's page shows the directory (tenant) id and cloud it is bound to.
Everything CMDash checks, what it records, and how to revoke it are described once, in the Entra ID guide. If you already connected Entra ID, the consent is already in place: signing in again is still required, so CMDash can prove the directory for this connection.
A per-directory Intune connection is read-only: CMDash's app holds no Intune write permission, so the estate write-back actions (assigning a configuration profile, syncing a device) are disabled for it, with the reason.
Step 1: Register (or reuse) an Entra ID application
If you already registered an app for Defender for Endpoint, Sentinel, or Entra ID in CMDash, reuse it and skip to Step 2.
- Sign in to the Azure portal.
- Go to Microsoft Entra ID → App registrations → New registration.
- Name it
CMDash. - Under Supported account types, choose Accounts in this organizational directory only.
- Leave Redirect URI blank — a client-credentials app does not use one.
- Click Register.
- Copy the Application (client) ID and the Directory (tenant) ID from the overview page.
Step 2: Grant the Graph permission
- In the app registration, go to API permissions → Add a permission.
- Choose Microsoft Graph → Application permissions (not Delegated — delegated permissions require a signed-in user and will not work here).
- Add
DeviceManagementManagedDevices.Read.All. - Click Grant admin consent for <your tenant>.
The permission must show Granted with a green check. Without admin consent the token is issued successfully but every Graph call returns 403 — a failure that looks like a permissions bug rather than a missing consent click.
Least privilege:
.Read.Allis read-only. Do not addDeviceManagementManagedDevices.PrivilegedOperations.Allor.ReadWrite.All— nothing in this integration can use them, and those permissions can wipe and retire devices.
Step 3: Create a client secret
- Go to Certificates & secrets → New client secret.
- Set a description and an expiry (24 months maximum).
- Copy the secret Value — not the Secret ID. The value is shown only once.
Note the expiry date. Entra client secrets expire, and when one does, syncs begin failing with a 401. See Credential Rotation below.
Step 4: Connect in CMDash
- Navigate to Integrations in your CMDash dashboard.
- Find Microsoft Intune and click Connect.
- CMDash uses the Azure credentials configured for your deployment (
AZURE_TENANT_ID,AZURE_CLIENT_ID,AZURE_CLIENT_SECRET); self-hosted operators set these in the environment and leaveAZURE_MULTI_TENANTunset. (On CMDash SaaS, use the per-directory flow instead.) - Click Save & Test Connection.
What Syncs
| Data Type | Graph API | Behaviour on failure |
|---|---|---|
| Managed device inventory — name, OS, OS version, encryption state, enrolment status, last sync | GET /v1.0/deviceManagement/managedDevices | Fails the sync — this is the only dataset |
How the numbers are computed
- Managed coverage counts devices whose
managementStateismanaged. A device that is retired, wiped, or unresponsive is enrolled but not contributing coverage, and is counted as inactive. - Disk encryption reads Graph's device-level
isEncryptedflag. Graph does not populate it for every platform; a device where it is absent is recorded as unknown, never as unencrypted, and is excluded from both sides of the encryption-coverage percentage. - OS version is stored exactly as Microsoft reports it (
10.0.19045,14.5,17.5.1) and is deliberately not parsed into a comparable version object at ingest. - iOS, iPadOS and Android devices are mapped to OS family
otherrather than being forced into one of Windows/macOS/Linux — misfiling them would inflate the denominator of any OS-specific control. - A device that has never synced is recorded with an epoch
lastSeenAt, never with "now".
Troubleshooting
- 403 on every call, but the connection test passed: Admin consent was not granted. Re-check Step 2 — the permission must show Granted, not merely Added.
- 401 Unauthorized after months of working syncs: The client secret expired. This is the single most common Intune/Graph failure. See Credential Rotation.
Delegatedpermission added by mistake: Graph will issue a token that carries no application permissions, so calls 403. Remove the delegated entry and add the Application one.- A per-directory connect was refused (administrator role required, different directory, wrong cloud, session mismatch): see the reasons in the Entra ID guide's troubleshooting — they are the same flow.
- Unhealthy right after connecting on SaaS: Microsoft can take a few minutes to apply a fresh consent. CMDash re-checks an Unhealthy connection every 30 minutes with a newly minted token and marks it Active once the check passes, after which scheduled syncs resume; Sync now retries sooner, each time with a newly minted token. If a sync has already failed on it, it stays Unhealthy until a sync succeeds (use Sync now).
- Device count is lower than the Intune console shows: The console includes devices in states this integration maps to inactive. Compare against Intune's All devices filtered to
Managed. - Encryption coverage is computed over fewer devices than your fleet: intended. Only devices where Graph populates
isEncryptedare in the denominator.
Rate Limits & Sync Behavior
| Setting | Value |
|---|---|
| Sync frequency | Every 4 hours by default (syncInterval is configurable per connection) |
| Pagination | Graph @odata.nextLink continuation, 1,000 records per page, capped at 5,000 records per sync |
| Rate limit handling | Routed through CMDash's shared token-bucket limiter, which paces requests across the page walk |
| Circuit breaker | Repeated failures open the breaker and the sync is skipped rather than hammering a throttled tenant |
| Failed sync retry | Job queue retries 3 times with exponential backoff (starting at 30s) — see docs/developers/dead-letter.md |
Credential Rotation
Entra client secrets expire (24 months maximum). Set a calendar reminder before the expiry date — an expired secret fails every sync with a 401 and there is no advance warning from Graph.
To rotate (self-hosted):
- In Azure: App registrations → CMDash → Certificates & secrets → New client secret. Create the new secret before deleting the old one; both are valid simultaneously.
- Update
AZURE_CLIENT_SECRETin your CMDash deployment (AZURE_GOV_CLIENT_SECRETfor a US Government registration). - Confirm a successful sync, then delete the old secret in Azure.
On CMDash SaaS there is nothing on your side to rotate: the secret belongs to CMDash's own app registration.
Known Limitations
- No screen-lock or compliance-policy detail. Graph exposes per-policy compliance through
deviceCompliancePolicyStates, a separate per-device call that would be an N+1 over the entire fleet on every sync. CMDash reports nothing rather than reading a bounded prefix, which would yield a compliance ratio over a biased sample. - No incidents or vulnerabilities. Intune is a management plane. Defender for Endpoint is the detection product and has its own CMDash adapter — claiming incidents here would double-count a signal CMDash already ingests from the correct source.
- Co-managed devices appear once. A device managed by both Intune and Configuration Manager is reported by Graph once; CMDash does not attempt to reconcile it against an SCCM inventory it cannot see.
- The 5,000-device ceiling is a truncation, not a sample. Larger fleets are cut off mid-walk, coverage percentages are computed over the truncated set, and the sync log carries a warning.