Query Details
let SensitiveMsGraphPermissions = externaldata(
EAMTierLevelName: string,
Category: string,
ScopeDisplayName: string
) [@"https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/refs/heads/main/Classification/Classification_MsGraphScopes.json"] with (format="multijson")
|;
let SignInsWithDelegatedScope = union SigninLogs, AADNonInteractiveUserSignInLogs
| where ResourceDisplayName == "Microsoft Graph"
// Enrichment of CAE, OAuthScope and Token Binding
| extend AuthenticationMethod = tostring(parse_json(AuthenticationDetails)[0].authenticationMethod)
| extend AuthenticationDetail = tostring(parse_json(AuthenticationDetails)[0].authenticationStepResultDetail)
| extend AuthProcessDetails = replace_string(AuthenticationProcessingDetails, " " , "")
| extend AuthProcessDetails = replace_string(AuthProcessDetails, "\r\n" , "")
| parse AuthProcessDetails with * "IsClientCapable\",\"value\":\"" IsClientCapable "\"" *
| parse AuthProcessDetails with * "IsCAEToken\",\"value\":\"" IsCaeToken "\"" *
| parse AuthProcessDetails with * "OauthScopeInfo\",\"value\":\"" OauthScopeInfo "\"}" *
| extend OAuthDelegatedScope = replace_string(OauthScopeInfo, '\\', '')
| extend TokenProtectionStatus = iff(isempty( TokenProtectionStatusDetails_dynamic ), todynamic(TokenProtectionStatusDetails_string), TokenProtectionStatusDetails_dynamic)
| extend SignInSessionStatus = tostring(TokenProtectionStatus.signInSessionStatus)
// Enrichment for AuthMethod and DeviceDetails
| extend AuthenticationMethod = tostring(parse_json(AuthenticationDetails)[0].authenticationMethod)
| extend AuthenticationDetail = tostring(parse_json(AuthenticationDetails)[0].authenticationStepResultDetail)
| extend DeviceDetail = iff(isempty( DeviceDetail_dynamic ), todynamic(DeviceDetail_string), DeviceDetail_dynamic)
| extend DeviceName = tostring(toupper(DeviceDetail.displayName))
| extend DeviceOS = tostring(parse_json(DeviceDetail).operatingSystem)
| extend DeviceTrust = tostring(parse_json(DeviceDetail).trustType)
| extend DeviceCompliance = tostring(parse_json(DeviceDetail).isCompliant)
| project TimeGenerated = CreatedDateTime, CorrelationId, UserPrincipalName, RiskLevelDuringSignIn, RiskState, AppDisplayName, ResourceDisplayName, tostring(OAuthDelegatedScope), AuthenticationMethod, AuthenticationDetail, DeviceName, DeviceOS, DeviceTrust, DeviceCompliance, IncomingTokenType, IsCaeToken, SignInSessionStatus;
SignInsWithDelegatedScope
| mv-expand parse_json(OAuthDelegatedScope)
| extend ScopeDisplayName = tostring(OAuthDelegatedScope)
| join kind=leftouter(
SensitiveMsGraphPermissions | project ScopePermissionTierLevel = tostring(EAMTierLevelName), tostring(Category), tostring(ScopeDisplayName)
) on ScopeDisplayName
| where isnotempty(ScopeDisplayName)
| extend ScopePermissionTierLevel = iff(isnotempty(ScopePermissionTierLevel), ScopePermissionTierLevel, "Unclassified")
| sort by TimeGenerated
| extend ScopePermissionDetails = bag_pack_columns(ScopeDisplayName, ScopePermissionTierLevel)
// Optional: Filter sign-ins with delegated permissions on Control Plane
//| where ScopePermissionTierLevel == "ControlPlane"
| summarize ScopePermissions = make_set(ScopePermissionDetails), ScopePermissionTierLevels = array_sort_asc(make_set(ScopePermissionTierLevel)) by TimeGenerated, CorrelationId, UserPrincipalName, RiskLevelDuringSignIn, RiskState, AppDisplayName, ResourceDisplayName, AuthenticationMethod, AuthenticationDetail, DeviceName, DeviceOS, DeviceTrust, DeviceCompliance, IncomingTokenType, IsCaeToken, SignInSessionStatus
This KQL query is designed to analyze sign-in logs related to Microsoft Graph, focusing on delegated permissions. Here's a simplified breakdown of what the query does:
Load Sensitive Permissions Data: It starts by loading a dataset of sensitive Microsoft Graph permissions from an external JSON file hosted on GitHub. This dataset includes information about the permission tier level, category, and scope display name.
Combine Sign-In Logs: It combines data from two sources: SigninLogs and AADNonInteractiveUserSignInLogs, filtering for entries where the resource display name is "Microsoft Graph".
Extract and Enrich Data: The query extracts and enriches various details from the sign-in logs:
Project Relevant Fields: It selects specific fields to focus on, such as the time of the sign-in, user principal name, risk level, application name, and various authentication and device details.
Expand and Join with Sensitive Permissions: The query expands the OAuth delegated scopes and joins them with the sensitive permissions data to identify the tier level and category of each scope.
Classify and Sort: It classifies scopes that don't have a tier level as "Unclassified" and sorts the results by the time of the sign-in.
Summarize Results: Finally, it summarizes the data by grouping it based on several fields and creating sets of scope permissions and their tier levels.
This query helps in identifying and analyzing sign-ins that involve sensitive Microsoft Graph permissions, providing insights into the risk levels and compliance of devices used during these sign-ins.

Thomas Naunheim
Released: June 11, 2026
Tables
Keywords
Operators