Skip to main content
CMDashCybersecurity Maturity Dashboard
← Back to Microsoft Purview (DLP)

Coming soon

Microsoft Purview (DLP) — Integration Setup

Note: This guide covers Microsoft Purview data-loss-prevention alerts. It is a different integration from Microsoft Defender for Endpoint (EDR) and Microsoft Defender for Cloud (cloud posture), even though all three are reached through an Azure app registration. You can connect any combination of them; they do not share a connection.

CMDash reads the alerts Purview's DLP engine actually raised, so your data-protection controls are evidenced by what was caught rather than by the policy document describing what should be.

Prerequisites

  • Microsoft 365 E5, or E3 plus the Microsoft 365 E5 Compliance add-on (DLP alerts in Microsoft Graph require a Purview-licensed tenant)
  • At least one Purview DLP policy published and enabled — a tenant with no enabled policy produces no alerts, and CMDash will correctly report zero rather than inventing coverage
  • An Entra ID (Azure AD) administrator who can grant admin consent to application permissions (Global Administrator or Privileged Role Administrator)
  • CMDash Essentials tier or above

How CMDash connects

Purview uses CMDash's Microsoft app registration with application permissions and an app-only token (the client-credentials grant) — no signed-in user, no refresh token. Which directory is read depends on how the deployment runs its Microsoft integrations; see How CMDash connects to Microsoft.

  • 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. Once it is, Integrations → Microsoft Purview (DLP) → Connect, choose your Microsoft cloud — Commercial, GCC, GCC High or DoD; Graph's security/alerts_v2 is published in all three — sign in as an active Global Administrator or Privileged Role Administrator, and accept the permissions for your organisation. The connection is bound to your directory. What CMDash checks and records is described once, in the Entra ID guide.
  • Self-hosted (single directory): Steps 1–4 below.

Step 1 (self-hosted): Register an Entra ID App

You can reuse the CMDash Integration app registration from the Defender guide if you already created one — add the permission in Step 2 to it and skip to Step 3.

  1. Go to Azure Portal → App registrations
  2. Click New registration
  3. Name: CMDash Integration
  4. Supported account types: Single tenant
  5. Click Register

No redirect URI is needed. This integration uses the OAuth2 client-credentials grant — an application identity, not a signed-in user — so there is no browser redirect in the flow.

Step 2 (self-hosted): Configure API Permissions

  1. In the app registration, go to API permissions → Add a permission
  2. Select Microsoft Graph → Application permissions
  3. Add:
    • SecurityAlert.Read.All — read security alerts, which is where Purview publishes DLP policy matches
  4. Click Grant admin consent for <your tenant>

SecurityAlert.Read.All covers every serviceSource on the Graph alerts collection, not only Purview. CMDash filters server-side to serviceSource eq 'dataLossPrevention' and never requests or stores the others.

Step 3 (self-hosted): Create a Client Secret

  1. Go to Certificates & secrets → New client secret
  2. Description: CMDash
  3. Expiry: 24 months (set a calendar reminder to rotate)
  4. Copy the Value immediately — it will not be shown again

Step 4 (self-hosted): Configure the deployment, then connect

The tenant id, client id and secret are server settings, not fields in the connect dialog.

  1. Set AZURE_TENANT_ID (Entra ID → Overview), AZURE_CLIENT_ID (the app registration) and AZURE_CLIENT_SECRET (from Step 3) in the API's environment, leave AZURE_MULTI_TENANT unset, and restart the API
  2. Navigate to Integrations in your CMDash dashboard
  3. Find Microsoft Purview (DLP) under Data Loss Prevention and click Connect — CMDash requests a token server-to-server and checks it against Graph before the connection goes active

What Syncs

Data TypeGraph APISync Frequency
DLP policy violations/v1.0/security/alerts_v2?$filter=serviceSource eq 'dataLossPrevention' (on graph.microsoft.com, graph.microsoft.us or dod-graph.microsoft.us, per the connection's cloud)Every 4 hours (configurable per integration)

What CMDash does not read

The matched content is never requested and never stored. A DLP alert exists because something sensitive was detected; the alert metadata (which policy, which severity, when, and the affected resource identifiers Graph returns) is what evidences the control. Pulling the matched text into a compliance platform would move the regulated data you are protecting into a second system — so CMDash reads the violation, not the violating content.

Why each sync fetches a rolling window, not just what is new

Each sync reads the last 35 days of alerts rather than only those created since the previous run. This is deliberate: CMDash stores the latest sync result per integration and re-derives your 30-day violation count from it, so an incremental-only fetch would make that count collapse toward zero after the first cycle — a tenant with real, ongoing violations would show a reassuring near-empty dashboard. The 35-day window gives the 30-day metric a margin.

Troubleshooting

  • 401 Unauthorized: Self-hosted: the client secret behind AZURE_CLIENT_SECRET expired, or admin consent was never granted — re-grant consent and update the secret. SaaS: the CMDash app was removed from your directory — reconnect.
  • A SaaS connect was refused (administrator role required, different directory, wrong cloud, session mismatch): see the Entra ID guide's troubleshooting — it is the same flow.
  • 403 Forbidden: SecurityAlert.Read.All is missing, or was added as a delegated rather than an application permission.
  • Connection succeeds but no violations appear: Confirm at least one DLP policy is published and enabled in the Purview compliance portal, and that it has actually matched something in the last 35 days. CMDash reports an empty result as empty — it will not present "no data" as "no violations" (see the sync status on the integration's detail page, which distinguishes the two).
  • Connection shows UNHEALTHY: The health monitor checks every 30 minutes. Repeated auth failures open the circuit breaker for this integration so a broken credential cannot burn your Graph quota; fix the credential and the breaker closes on the next successful call.

Rate Limits & Sync Behavior

SettingValue
Sync frequencyEvery 4 hours (configurable per integration)
Lookback per sync35 days
Rate limit handlingEvery request is paced through CMDash's per-(tenant, provider) token bucket
Vendor error (including 429)Fails that sync attempt; the job queue retries it
Failed sync retryJob queue retries 3 times with exponential backoff, then the dead-letter queue — see docs/developers/dead-letter.md

Credential Rotation

On CMDash SaaS there is nothing on your side to rotate: the secret belongs to CMDash's own app registration.

Self-hosted: Entra ID client secrets have a maximum lifetime of 24 months, and CMDash does not warn before one expires. Add the new secret before the old one expires to avoid a sync outage.

  1. Azure Portal → App registrations → CMDash Integration
  2. Certificates & secrets → New client secret, copy the Value
  3. Update AZURE_CLIENT_SECRET in the API's environment and restart the API
  4. Once the next sync succeeds, delete the old secret in Azure

The secret is a server setting shared by every CMDash Microsoft integration (Defender, Purview, Entra ID, Intune, Sentinel), so rotating it affects all of them at once.

Ready to see your posture?

Start a 30-day free trial of any paid plan — a card is required, and it converts unless you cancel — or sign up for Free with no card at all.