Microsoft Graph API Integration
8 minute read
Overview
Microsoft Graph is the gateway to data and intelligence in Microsoft 365, providing unified access to Azure Active Directory, Office 365, Enterprise Mobility, and Windows services. This integration allows you to retrieve comprehensive audit logs including directory audits, sign-in logs, provisioning logs, and security alerts for monitoring and compliance.
The Microsoft Graph API uses OAuth2 client credentials flow and OData query capabilities for filtering and pagination.
Endpoints
Endpoint | Description | API Path |
---|---|---|
Directory Audit Logs | Administrative actions and configuration changes | /auditLogs/directoryAudits |
Sign-In Logs | User authentication events | /auditLogs/signIns |
Provisioning Logs | User and group provisioning activities | /auditLogs/provisioning |
Security Alerts | Security alerts from Microsoft Defender | /security/alerts |
Authentication Method
Microsoft Graph uses OAuth2 client credentials flow with the following components:
- Tenant ID: Your Azure AD tenant identifier
- Client ID: Your registered application client ID
- Client Secret: Your application client secret
- Scope:
https://graph.microsoft.com/.default
The OAuth2 flow is automatically handled by the HTTP Pull input using the oauth_client_credentials
authorization strategy.
Environment Variables
Set these environment variables for secure credential management:
# Azure AD Tenant ID
export AZURE_TENANT_ID="your-tenant-id-here"
# Application (client) ID from Azure App Registration
export AZURE_CLIENT_ID="your-client-id-here"
# Client Secret from Azure App Registration
export AZURE_CLIENT_SECRET="your-client-secret-here"
# Optional: Graph API endpoint (defaults to global)
export GRAPH_API_ENDPOINT="https://graph.microsoft.com"
Configuration Examples
This section provides configurations for all major Microsoft Graph API audit log types:
Directory Audit Logs
Monitor administrative actions and configuration changes:
nodes:
- name: graph_directory_audits
type: http_pull_input
endpoint: https://graph.microsoft.com/v1.0/auditLogs/directoryAudits
method: GET
pull_interval: 5m
# OAuth2 Client Credentials Authentication
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://graph.microsoft.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
parameters:
- name: "$orderby"
value: "activityDateTime asc"
- name: "$top"
value: "50"
parameter_expressions:
- name: "$filter"
value_expression: Concat(["activityDateTime ge ", FormatTime(Now() - Duration("5m10s"), "%Y-%m-%dT%H:%M:%SZ")], "")
Sign-In Logs
Monitor user authentication events:
nodes:
- name: graph_signin_logs
type: http_pull_input
endpoint: https://graph.microsoft.com/v1.0/auditLogs/signIns
method: GET
pull_interval: 5m
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://graph.microsoft.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
parameters:
- name: "$orderby"
value: "createdDateTime asc"
- name: "$top"
value: "50"
parameter_expressions:
- name: "$filter"
value_expression: Concat(["createdDateTime ge ", FormatTime(Now() - Duration("5m10s"), "%Y-%m-%dT%H:%M:%SZ")], "")
Provisioning Logs
Track user and group provisioning activities:
nodes:
- name: graph_provisioning_logs
type: http_pull_input
endpoint: https://graph.microsoft.com/v1.0/auditLogs/provisioning
method: GET
pull_interval: 5m
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://graph.microsoft.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
parameters:
- name: "$orderby"
value: "activityDateTime asc"
- name: "$top"
value: "50"
parameter_expressions:
- name: "$filter"
value_expression: Concat(["activityDateTime ge ", FormatTime(Now() - Duration("5m10s"), "%Y-%m-%dT%H:%M:%SZ")], "")
Security Alerts
Retrieve security alerts from Microsoft Defender:
nodes:
- name: graph_security_alerts
type: http_pull_input
endpoint: https://graph.microsoft.com/v1.0/security/alerts
method: GET
pull_interval: 5m
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://graph.microsoft.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
parameters:
- name: "$orderby"
value: "createdDateTime asc"
- name: "$top"
value: "50"
parameter_expressions:
- name: "$filter"
value_expression: Concat(["createdDateTime ge ", FormatTime(Now() - Duration("5m10s"), "%Y-%m-%dT%H:%M:%SZ")], "")
Configuration with Environment Variables
For production deployments, use environment variables with OTTL expressions:
nodes:
- name: graph_directory_audits
type: http_pull_input
endpoint_expression: Concat([EDXEnv("GRAPH_API_ENDPOINT", "https://graph.microsoft.com"), "/v1.0/auditLogs/directoryAudits"], "")
method: GET
pull_interval: 5m
# OAuth2 with environment variables requires static configuration
# Edge Delta does not support OTTL expressions in authorization block
authorization:
strategy: oauth_client_credentials
client_credentials:
token_url: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/v2.0/token
client_id: YOUR_CLIENT_ID
client_secret: YOUR_CLIENT_SECRET
scopes:
- https://graph.microsoft.com/.default
header_templates:
- header: Authorization
value: Bearer $ACCESS_TOKEN
parameters:
- name: "$orderby"
value: "activityDateTime asc"
- name: "$top"
value: "50"
parameter_expressions:
- name: "$filter"
value_expression: Concat(["activityDateTime ge ", FormatTime(Now() - Duration("5m10s"), "%Y-%m-%dT%H:%M:%SZ")], "")
Note
The OAuth2 authorization block does not support OTTL expressions. Store credentials securely in your Edge Delta agent configuration or use a secrets management system.API Endpoints Reference
Log Type | API Version | Endpoint | Description |
---|---|---|---|
Directory Audits | v1.0 | /auditLogs/directoryAudits | Administrative actions and config changes |
Sign-In Logs | v1.0 | /auditLogs/signIns | User authentication attempts and results |
Provisioning Logs | v1.0 | /auditLogs/provisioning | User and group provisioning activities |
Security Alerts | v1.0 | /security/alerts | Security alerts from Microsoft Defender |
Time Windows and Pull Intervals
Each endpoint uses a consistent 5-minute and 10-second lookback window to prevent data gaps:
Endpoint | Time Window | Pull Interval | Rationale |
---|---|---|---|
Directory Audits | 5m10s | 5 minutes | Admin actions, moderate frequency |
Sign-In Logs | 5m10s | 5 minutes | High-frequency auth events |
Provisioning Logs | 5m10s | 5 minutes | User/group provisioning events |
Security Alerts | 5m10s | 5 minutes | Critical security events |
OAuth2 Client Credentials Details
The Microsoft Graph API uses OAuth2 client credentials flow for application authentication:
- Token Request: POST request to Azure AD token endpoint
- Token Response: Bearer token with expiration time
- Automatic Refresh: HTTP Pull input handles token renewal
- Header Injection: Bearer token automatically added to requests
The OAuth2 flow is automatically handled by Edge Delta using:
authorization.strategy: oauth_client_credentials
for token managementheader_templates
for bearer token injection- Automatic token refresh before expiration
Important: Application Permissions Required
Microsoft Graph requires application-level permissions (not delegated) for accessing audit logs. Ensure your Azure AD application has the correct permissions and admin consent has been granted.OAuth2 Token Flow Breakdown
Here’s how the OAuth2 client credentials flow works:
# 1. Token Request (handled automatically by Edge Delta)
POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={client-id}&
client_secret={client-secret}&
scope=https://graph.microsoft.com/.default&
grant_type=client_credentials
# 2. Token Response
{
"token_type": "Bearer",
"expires_in": 3599,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOi..."
}
# 3. API Request (automatic header injection)
GET https://graph.microsoft.com/v1.0/auditLogs/directoryAudits
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOi...
Token Management Features:
- Automatic Renewal: Tokens refreshed 5 minutes before expiration
- Error Handling: 401 responses trigger immediate token refresh
- Secure Storage: Tokens stored in memory only, never logged
- Header Injection:
$ACCESS_TOKEN
variable automatically populated
Azure AD Application Setup
1. Register Application in Azure Portal
Navigate to Azure Active Directory > App registrations:
- Click “New registration”
- Enter name: “EdgeDelta Graph API Integration”
- Select “Accounts in this organizational directory only”
- Leave Redirect URI blank (not needed for client credentials)
- Click “Register”
2. Configure Required API Permissions
Add Microsoft Graph Application permissions (not Delegated):
Permission | Description | Required For |
---|---|---|
AuditLog.Read.All | Read all audit log data | Directory audits, sign-in logs, provisioning logs |
SecurityEvents.Read.All | Read security events | Security alerts |
Setup Steps:
- Go to API permissions > Add a permission
- Select Microsoft Graph > Application permissions
- Search and add required permissions above
- Click “Grant admin consent for [tenant]” (admin required)
3. Create Client Secret
- Navigate to Certificates & secrets > Client secrets
- Click “New client secret”
- Enter description: “EdgeDelta HTTP Pull Integration”
- Set expiration (recommend 12-24 months)
- Click “Add” and copy the secret value immediately
4. Collect Configuration Values
From your Azure AD application:
- Tenant ID: Found on Overview page under “Directory (tenant) ID”
- Client ID: Found on Overview page under “Application (client) ID”
- Client Secret: The value you copied when creating the secret
OData Query Parameters
Microsoft Graph uses OData v4 query parameters for filtering and data selection:
Parameter | Purpose | Example |
---|---|---|
$filter | Filter results by criteria | createdDateTime ge 2024-01-01T00:00:00Z |
$orderby | Sort results | activityDateTime asc |
$top | Limit results per page | 50 |
$select | Choose specific fields | id,createdDateTime,userPrincipalName |
Advanced OData Examples
# Time-based filtering
$filter: "createdDateTime ge 2024-01-01T00:00:00Z and createdDateTime le 2024-01-02T00:00:00Z"
# Status filtering for sign-ins
$filter: "status/errorCode eq 0"
# Risk level filtering
$filter: "riskLevelAggregated eq 'high'"
# Application filtering
$filter: "appDisplayName eq 'Microsoft 365'"
# User filtering
$filter: "startswith(userPrincipalName, 'admin')"
# Multiple conditions
$filter: "createdDateTime ge 2024-01-01T00:00:00Z and status/errorCode ne 0"
API Documentation
For detailed API documentation, visit:
- Microsoft Graph REST API Overview - Complete API documentation
- Directory Audits API - Directory audit log endpoint
- Sign-in Logs API - Authentication log endpoint
- Security Alerts API - Security alert endpoint
- OAuth 2.0 Client Credentials Flow - Authentication flow details
Rate Limiting
Microsoft Graph implements throttling based on multiple factors:
- Per-application limits: Varies by endpoint and license tier
- Per-tenant limits: Shared across all applications in tenant
- Resource-specific limits: Different limits for different data types
- License-based limits: Higher limits for premium licenses
The configured 5-minute intervals respect these limits while ensuring continuous data collection.
Troubleshooting
401 Unauthorized:
- Verify
AZURE_CLIENT_ID
andAZURE_CLIENT_SECRET
environment variables - Check that application permissions are correctly configured
- Ensure admin consent has been granted for application permissions
- Verify tenant ID in OAuth2 token URL is correct
403 Forbidden:
- Missing required Microsoft Graph API permissions
- Admin consent not granted (check Azure AD audit logs)
- Conditional access policies may be blocking the application
- Application may be disabled or restricted
400 Bad Request:
- Invalid OData query syntax in
$filter
parameter - Date format incorrect (must be ISO 8601:
YYYY-MM-DDTHH:MM:SSZ
) - Field names in filter don’t exist for the endpoint
- Invalid
$orderby
or$select
parameters
429 Too Many Requests:
- API rate limits exceeded
- Reduce query frequency or implement exponential backoff
- Check response headers for
Retry-After
guidance - Consider distributing load across multiple applications
Empty Results:
- Check time range in
$filter
parameter is reasonable - Verify data exists for the specified time period
- Some audit logs have processing delays (up to 15 minutes)
- Ensure clock synchronization between systems
Security Best Practices
- Credential Security: Store client secrets securely using Azure Key Vault or similar
- Regular Rotation: Rotate client secrets every 12-24 months
- Least Privilege: Grant only required API permissions
- Monitor Access: Enable Azure AD sign-in logs to monitor application access
- Conditional Access: Apply appropriate conditional access policies
- Certificate Authentication: Consider using certificates instead of secrets for production
- Network Security: Restrict application access using IP ranges if possible
Sample Log Data
Directory Audit Log Sample
{
"id": "Directory_ABCD1234_20240101_001",
"category": "UserManagement",
"activityDateTime": "2024-01-01T10:00:00Z",
"activityDisplayName": "Add user",
"initiatedBy": {
"user": {
"userPrincipalName": "admin@company.com",
"displayName": "Admin User"
}
},
"targetResources": [
{
"displayName": "john.doe@company.com",
"type": "User",
"userPrincipalName": "john.doe@company.com"
}
],
"result": "success"
}
Sign-In Log Sample
{
"id": "SignIn_EFGH5678_20240101_001",
"createdDateTime": "2024-01-01T10:05:00Z",
"userPrincipalName": "john.doe@company.com",
"appDisplayName": "Microsoft 365",
"status": {
"errorCode": 0,
"failureReason": null,
"additionalDetails": "MFA completed successfully"
},
"location": {
"city": "Seattle",
"state": "Washington",
"countryOrRegion": "US"
},
"deviceDetail": {
"browser": "Chrome 120.0.0.0",
"operatingSystem": "Windows 11"
},
"riskLevelAggregated": "low"
}