Microsoft Graph API Integration

Configure HTTP Pull to retrieve audit logs from all Microsoft Graph API endpoints including directory audits, sign-in logs, provisioning logs, and security alerts using OAuth2 client credentials authentication.

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

EndpointDescriptionAPI Path
Directory Audit LogsAdministrative actions and configuration changes/auditLogs/directoryAudits
Sign-In LogsUser authentication events/auditLogs/signIns
Provisioning LogsUser and group provisioning activities/auditLogs/provisioning
Security AlertsSecurity 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")], "")

API Endpoints Reference

Log TypeAPI VersionEndpointDescription
Directory Auditsv1.0/auditLogs/directoryAuditsAdministrative actions and config changes
Sign-In Logsv1.0/auditLogs/signInsUser authentication attempts and results
Provisioning Logsv1.0/auditLogs/provisioningUser and group provisioning activities
Security Alertsv1.0/security/alertsSecurity 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:

EndpointTime WindowPull IntervalRationale
Directory Audits5m10s5 minutesAdmin actions, moderate frequency
Sign-In Logs5m10s5 minutesHigh-frequency auth events
Provisioning Logs5m10s5 minutesUser/group provisioning events
Security Alerts5m10s5 minutesCritical security events

OAuth2 Client Credentials Details

The Microsoft Graph API uses OAuth2 client credentials flow for application authentication:

  1. Token Request: POST request to Azure AD token endpoint
  2. Token Response: Bearer token with expiration time
  3. Automatic Refresh: HTTP Pull input handles token renewal
  4. 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 management
  • header_templates for bearer token injection
  • Automatic token refresh before expiration

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:

  1. Click “New registration”
  2. Enter name: “EdgeDelta Graph API Integration”
  3. Select “Accounts in this organizational directory only”
  4. Leave Redirect URI blank (not needed for client credentials)
  5. Click “Register”

2. Configure Required API Permissions

Add Microsoft Graph Application permissions (not Delegated):

PermissionDescriptionRequired For
AuditLog.Read.AllRead all audit log dataDirectory audits, sign-in logs, provisioning logs
SecurityEvents.Read.AllRead security eventsSecurity alerts

Setup Steps:

  1. Go to API permissions > Add a permission
  2. Select Microsoft Graph > Application permissions
  3. Search and add required permissions above
  4. Click “Grant admin consent for [tenant]” (admin required)

3. Create Client Secret

  1. Navigate to Certificates & secrets > Client secrets
  2. Click “New client secret”
  3. Enter description: “EdgeDelta HTTP Pull Integration”
  4. Set expiration (recommend 12-24 months)
  5. 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:

ParameterPurposeExample
$filterFilter results by criteriacreatedDateTime ge 2024-01-01T00:00:00Z
$orderbySort resultsactivityDateTime asc
$topLimit results per page50
$selectChoose specific fieldsid,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:

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 and AZURE_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

  1. Credential Security: Store client secrets securely using Azure Key Vault or similar
  2. Regular Rotation: Rotate client secrets every 12-24 months
  3. Least Privilege: Grant only required API permissions
  4. Monitor Access: Enable Azure AD sign-in logs to monitor application access
  5. Conditional Access: Apply appropriate conditional access policies
  6. Certificate Authentication: Consider using certificates instead of secrets for production
  7. 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"
}