---
title: "Microsoft Graph collector"
canonical: "https://docs.devo.com/space/latest/94656642/Microsoft%20Graph%20collector"
format: markdown
---
> Macro (toc)

## Purpose

An analyst wants to detect exfiltration of contracts and financial data.  With the Microsoft Graph collector, alerts about Microsoft 365 Copilot activity (including **Word** and **Excel**) are imported to Devo.  As a result, the analyst can set up an alert that triggers when Microsoft identifies a compromised user.  When the alert fires, the analyst can check Devo to see if the compromised user has moved laterally into non-Microsoft systems.

The Graph collector can also send Entra ID data to Devo.  Due to Graph’s low [rate limits](https://learn.microsoft.com/en-us/graph/throttling-limits), Devo recommends using the [Azure Event Hub](https://devodocs.atlassian.net/wiki/spaces/latest/pages/1198522408) collector to send Entra ID authentication data.

## Example tables

| **Table** | **Description** |
| --- | --- |
| [cloud.azure](https://devodocs.atlassian.net/wiki/spaces/latest/pages/322764842) | Data from Graph, Event Hubs, VM Metrics, Entra ID, and other sources. |
| cloud.[brand].[type].alerts_v2 | Alerts from Graph relating to Microsoft services. |
| cloud.azure.ad.* | Entra ID identity and access management logs. |
| cloud.azure.ad.signin_all | This union table combines all the different Entra ID authentication logs. |
| [auth.all](https://devodocs.atlassian.net/wiki/spaces/latest/pages/95126107) | Authentication logs, including Entra ID. |

## Authorize It

It will take several hours to configure the Graph collector.  Administrator permissions are required.  Microsoft credentials are confusing.  Before beginning, be aware of the [different credential fields](https://devodocs.atlassian.net/wiki/spaces/latest/pages/1086816286).

1. Go to [Azure Portal](https://portal.azure.com/) and search for App registration. Then click on **App registrations**.

![image-20260708-191717.png](media://cefaf56e-1fb4-41a6-b030-b31386abdcca)

2. Open **New registration**.

![image-20250314-193615.png](media://1229f784-e06e-43dd-8f81-9844c77a48d2)

3. On the **Register and Application** page:
  1. Name the application.
  2. In **Supported Accounts types**, select “Any Entra ID Tenant + Personal Microsoft accounts.”
  3. Click **Register**.

![image-20260708-191935.png](media://fc19860f-3f89-4a7e-b172-c74328a170c7)

4. App registration will open. Click on** your app** to configure it and give it permissions.

![image-20250314-194922.png](media://87671c88-1e0f-445f-935d-0d8e1585529f)

 

5. Search for **Authentication** on the left-menu side, then choose **Add Redirect URI** and select **Mobile and desktop application**.

![image-20260708-192157.png](media://c00fed56-928f-471f-94a9-b6fbc41ef188)

6. Select the redirect URI *https://login.microsoftonline.com/common/oauth2/nativeclient* and click **Configure**.

![image-20260708-192251.png](media://deda7ec3-20a4-46e5-8449-6db20718165f)

7. Open API permissions and select Microsoft Graph.
8. Select Application Permissions.
9. Add these permissions:

- `SecurityEvents.Read.All`.
- `AuditLog.Read.All`
- `Directory.Read.All`
- `User.Read.All`
- `SecurityAlert.Read.All`
  

8. Select Grant admin consent.
9. After consent, the five application permissions will have green check marks.

![image-20250401-153347.png](media://938c0f47-4c7c-4b7f-8180-3153b65e3274)

9. Go to Certificates & Secrets and select **New client secret**.
10. Add the secret.

![image-20250320-174440.png](media://97f821f4-4242-486b-9536-65e77471c308)

> ❌ **Data loss** warning: At the secret expiration time, the collector will stop working until the secret is replaced.

11. Copy the secret value.

> ⚠️ **Save** the client secret **value**. It will only be shown once.
> ⚠️ 
> ⚠️ 
> ⚠️ The **value** <u>[contains a tilde ~ character.](https://devodocs.atlassian.net/wiki/spaces/latest/pages/1086816286)</u>

![image-20250320-174815.png](media://7a2f0819-abc3-4309-b273-89e172000846)

12. In the App registration’s overview, copy the **Application (client) ID** and the **Directory (tenant) ID**.

![image-20250320-174953.png](media://dfc55dca-5b19-40d2-80de-50cef92f55af)

## Run It

In the Cloud Collector App, [create a Microsoft Graph Collector instance](https://devodocs.atlassian.net/wiki/spaces/latest/pages/409305131).  **Remove **the default collector parameters and insert this parameters template, replacing the values enclosed in `< >`.  

```
{
  "inputs": {
    "microsoft_graph_audit": {
      "credentials": {
        "client_id": "<CLIENT_ID>",
        "client_secret": "<CLIENT_SECRET>",
        "tenant_id": "<TENANT_ID>"
      },
      "enabled": true,
      "id": "<UNIQUE ID>",
      "services": {
        "directory_audits": {},
        "provisioning_audits": {},
        "signIns": {},
        "signIns_v2": {}
      }
    },
    "microsoft_graph_security": {
      "credentials": {
        "client_id": "<CLIENT_ID>",
        "client_secret": "<CLIENT_SECRET>",
        "tenant_id": "<TENANT_ID>"
      },
      "enabled": true,
      "id": "<DIFFERENT UNIQUE ID>",
      "services": {
        "alerts": {},
        "alerts_v2": {},
        "secure_score_control_profiles": {},
        "secure_scores": {},
        "incidents": {}
      }
    }
  }
}
```

The secret must be a [secret value](https://devodocs.atlassian.net/wiki/spaces/latest/pages/1086816286) containing a tilde.

Due to Graph’s low rate limits, Devo recommends using the [Azure Event Hub](https://devodocs.atlassian.net/wiki/spaces/latest/pages/1198522408) collector to send Entra ID authentication data.  To select this option, remove the two signIns services after creating the Event Hub collector.

## Secure It

> ✅ Graph Alerts tables have a *evidence* column.  In the *evidence* column, right click the cell and select **Pretty print** to get a nice view of the evidence of an attack.

#### Malicious files

An analyst wants to identify user accounts associated with malicious files.  If the files identified by Graph are malware, the malware should be removed or isolated.  If the files are data exfiltration, the account should be disabled before more data can be exfiltrated.

```
from cloud.office365.cloud_apps.alerts_v2

//In most cases, there is only one user in the evidence.
group by str(jqeval(jqcompile(".[0].userAccount.userPrincipalName"),jsonparse(evidence))) as user,
description
//Count the files in the alerts.
//There may be files in the evidence which are not in the description.
select sum(length(split(evidence,"fileName"))-1) as files
//Exclude alerts with no files.
where files>0
select first(eventdate) as infection_report_time
```

#### Malicious network activity

An analyst wants to block attacks using a firewall.  If a user is connecting from two countries simultaneously or an application has engaged in phishing, blocking the IP may delay the attack.

```
from cloud.office365.cloud_apps.alerts_v2

//In most cases, there is only one user in the evidence.
group by description
//Count the IP addresses in the alerts.
//There may be addresses in the evidence which are not in the description.
select sum(length(split(evidence,"ipAddress"))-1) as ip_addresses
//Exclude alerts with no addresses.
where ip_addresses>0
select first(eventdate) as incident_report_time
```

##### Suspicious authentication in Entra ID

An analyst wants to use Microsoft’s models to identify accounts with suspicious authentication behavior.  The evidence associated with the alerts can be used to determine if the accounts should be deactivated.

```
from cloud.azure.ad.alerts_v2
group by description,
str(jqeval(jqcompile(".[0].userAccount.userPrincipalName"),jsonparse(evidence))) as user
```

#### SQL injection

A security researcher wants to identify SQL injection attacks to determine if web apps are protected.  Graph provides a list of attacks which can be correlated with the database audit log (such as `cloud.azure.sql.securityauditevents`) to determine the malicious SQL queries.

```
from cloud.msgraph.security.alerts_v2
where weakhas(description,"SQL Injection")
```

### Penetration testing

A CISO who has purchased penetration testing wishes to identify the testing methods (hardware and software) used by the service provider and determine the effectiveness of Graph at identifying penetration testing.

```
from cloud.msgraph.security.alerts_v2
where weakhas(description,"penetration") 
```

### Code injection

While responding to a malware campaign that injects code into processes, a security researcher wants to identify unresolved incidents detected by Microsoft Defender.

```
from cloud.msgraph.security.incident 
where eq(display_name,"Suspicious process injection observed") 
group by incident_web_url 
select last(status) as status 
where not eq(status,"resolved")
```


## Monitor It

In normal operation, Graph alerts are infrequent.  Create an [inactivity alert](https://docs.devo.com/space/latest/95126785/Inactivity+alert) to detect periods when the API does not report that no new alerts are available.

```
from devo.collectors.out 
where toktains(collector_image,"ms-graph-collector-if:"), toktains(msg,"Number of events received: 0;"), 
has(service_name,"alerts") or has(service_name,"signIns")
select split(hostname,"-",1) as collector_id
```

Set the inactivity alert to keep track of the `collector_id` and `service_name`.  The alert may trigger if the Graph API fails or if there is an unusual amount of data arriving at Graph.

## Legacy Graph APIs

Microsoft will remove the legacy alerts API from Graph “[by April 2026](https://learn.microsoft.com/en-us/graph/api/resources/security-api-overview?view=graph-rest-1.0).”  To avoid impact on your queries, use the tables named `alerts_v2`.  

## Permissions

| **Devo service** | **Graph Resource** | **Required permissions** | **Microsoft documentation** |
| --- | --- | --- | --- |
| `alerts` | `alerts` | `SecurityEvents.Read.All` | [List alerts](https://docs.microsoft.com/en-us/graph/api/alert-list?view=graph-rest-1.0&tabs=http#permissions) |
| `alerts_v2` | `alerts_v2` | `SecurityAlert.Read.All` | [List alerts_v2](https://learn.microsoft.com/en-us/graph/api/security-list-alerts_v2?view=graph-rest-1.0&tabs=http) |
| `secure_scores` | `secureScores` | `SecurityEvents.Read.All` | [List secureScores](https://docs.microsoft.com/en-us/graph/api/security-list-securescores?view=graph-rest-1.0&tabs=http) |
| `secure_score_control_profiles` | `secureScoreControlProfiles` | `SecurityEvents.Read.All` | [List secureScoreControlProfiles](https://docs.microsoft.com/en-us/graph/api/security-list-securescorecontrolprofiles?view=graph-rest-1.0&tabs=http) |
| `directory_audit` | `directoryAudits` | `AuditLog.Read.All`<br>`Directory.Read.All` | [List directoryAudits](https://docs.microsoft.com/en-us/graph/api/directoryaudit-list?view=graph-rest-1.0&tabs=http) |
| `provisioning_audit` | `provisioningObjectSummary` | `AuditLog.Read.All`<br>`Directory.Read.All` | [List provisioningObjectSummary](https://docs.microsoft.com/en-us/graph/api/provisioningobjectsummary-list?view=graph-rest-1.0&tabs=http#permissions) |
| `signIn` | `signIns` | `AuditLog.Read.All`<br>`Directory.Read.All` | [List signIns](https://docs.microsoft.com/en-us/graph/api/signin-list?view=graph-rest-1.0&tabs=http#permissions) |
| Required for all services | `authentication` | `User.Read` | [Microsoft Graph permissions](https://docs.microsoft.com/en-us/graph/permissions-reference#remarks-15) |
| Required for all services | `authentication` | `User.Read.All` | [Microsoft Graph permissions](https://learn.microsoft.com/en-us/graph/permissions-reference#remarks-15) |