Consent Fix Hunting Confidence On Token And Network Signals
Query
let Lookback = 2d;
let AffectedApps = dynamic([
"Microsoft Azure CLI",
"Microsoft Azure PowerShell",
"Microsoft Graph Command Line Tools"
]);
let BrowserProcesses = dynamic([
"msedge.exe",
"chrome.exe",
"iexplore.exe",
"firefox.exe",
"com.apple.Safari",
"com.microsoft.edgemac",
"com.microsoft.edgemac.helper"
]);
union SigninLogs, AADNonInteractiveUserSignInLogs
| where CreatedDateTime > ago(Lookback)
| where AppDisplayName in~ (AffectedApps)
| extend TokenProtectionStatus = iff(isempty(TokenProtectionStatusDetails_dynamic), todynamic(TokenProtectionStatusDetails_string), TokenProtectionStatusDetails_dynamic)
| extend
SignInSessionStatusCode = TokenProtectionStatus.signInSessionStatus
| project-rename UniqueTokenId = UniqueTokenIdentifier
| where ResultType == "0"
| join kind = leftouter (NetworkAccessTraffic
| project UniqueTokenId, InitiatingProcessName)
on UniqueTokenId
| project
InitialSignInTime = CreatedDateTime,
AppDisplayName,
InitialResource = ResourceDisplayName,
UserPrincipalName,
InitiatingProcessName,
SessionId,
InitialSignInUti = UniqueTokenId,
InitialIpAddress = IPAddress,
InitialAsn = AutonomousSystemNumber,
InitialSignInSessionStatus = tostring(SignInSessionStatusCode),
InitialIsGsa = IsThroughGlobalSecureAccess,
InitialTokenType = IncomingTokenType
| join kind = inner (
union SigninLogs, AADNonInteractiveUserSignInLogs
| where Lookback == (Lookback)
| where AppDisplayName in~ (AffectedApps)
| where ResultType == "0"
| extend TokenProtectionStatus = iff(isempty(TokenProtectionStatusDetails_dynamic), todynamic(TokenProtectionStatusDetails_string), TokenProtectionStatusDetails_dynamic)
| extend
TokenProtection = TokenProtectionStatus.signInSessionStatus,
SignInSessionStatusCode = TokenProtectionStatus.signInSessionStatus
| project
SignInTime = CreatedDateTime,
ResourceDisplayName,
SignInSessionStatus = tostring(SignInSessionStatusCode),
SessionId,
UniqueTokenIdentifier,
IPAddress,
Asn = AutonomousSystemNumber,
IsGsa = IsThroughGlobalSecureAccess,
TokenType = IncomingTokenType
)
on SessionId
| where SignInTime > InitialSignInTime
| project-away SessionId1
| project-reorder
InitialSignInTime,
SignInTime,
SessionId,
UserPrincipalName,
AppDisplayName,
InitialResource,
ResourceDisplayName,
InitialSignInSessionStatus,
SignInSessionStatus,
InitialIpAddress,
IPAddress,
InitialAsn,
Asn,
InitialIsGsa,
IsGsa
| extend WithinAuthCodeExpirationTime = SignInTime - InitialSignInTime > 12m
| extend ConfidenceScore = case(
InitiatingProcessName in~ (BrowserProcesses) and InitialSignInSessionStatus != SignInSessionStatus,
"Very high",
(InitialSignInSessionStatus != SignInSessionStatus and InitialAsn != Asn) or (InitialIsGsa != IsGsa and SignInSessionStatus != "bound"),
"High",
(InitialAsn != Asn and WithinAuthCodeExpirationTime == true) and (InitialSignInSessionStatus != SignInSessionStatus and InitialTokenType != TokenType),
"Medium",
(SignInTime - InitialSignInTime > 5s) and (SignInTime - InitialSignInTime < 720s),
"Low",
"None"
)
| extend UseCaseDescription = case(
InitiatingProcessName in~ (BrowserProcesses) and InitialSignInSessionStatus != SignInSessionStatus,
"Browser Auth Code Flow used instead of WAM based on GSA logs",
(InitialSignInSessionStatus != SignInSessionStatus and InitialAsn != Asn),
"Auth Code Flow used instead of WAM and ASN changed between sign-ins",
(InitialIsGsa != IsGsa and SignInSessionStatus != "bound"),
"Change from compliant network (GSA) during authentication and initial token unbound",
(InitialAsn != Asn and WithinAuthCodeExpirationTime == true) and (InitialSignInSessionStatus != SignInSessionStatus and InitialTokenType != TokenType),
"ASN changed during authentication, seconds authentication within 10 minutes, token bound status changed",
""
)
| extend SignIn = bag_pack_columns(SignInTime, SignInSessionStatus, ResourceDisplayName, Asn, IPAddress, IsGsa, UniqueTokenIdentifier, TokenType)
| summarize SignIns = make_set(SignIn)
by
InitialSignInTime,
UserPrincipalName,
AppDisplayName,
InitialSignInSessionStatus,
SessionId,
ConfidenceScore,
UseCaseDescription,
InitialIsGsa,
Asn,
IPAddress,
InitialTokenType,
InitiatingProcessName
| sort by InitialSignInTimeExplanation
This KQL query is designed to analyze sign-in activities for specific applications over the past two days. Here's a simplified breakdown of what the query does:
-
Define Variables:
Lookback: Sets the time frame to the last 2 days.AffectedApps: Lists the applications of interest, specifically Microsoft Azure CLI, Microsoft Azure PowerShell, and Microsoft Graph Command Line Tools.BrowserProcesses: Lists common browser processes like Edge, Chrome, Firefox, etc.
-
Data Collection:
- Combines data from
SigninLogsandAADNonInteractiveUserSignInLogstables. - Filters records to include only those created within the last 2 days and related to the specified applications.
- Extracts and processes token protection status details.
- Combines data from
-
Join with Network Data:
- Joins the sign-in data with
NetworkAccessTrafficto get the initiating process name using a left outer join.
- Joins the sign-in data with
-
Initial Sign-In Data:
- Projects relevant fields such as sign-in time, application name, user principal name, session ID, IP address, and token type.
-
Subsequent Sign-In Data:
- Joins with the same sign-in logs to find subsequent sign-ins for the same session.
- Ensures that these subsequent sign-ins occurred after the initial sign-in.
-
Analysis and Scoring:
- Calculates the time difference between initial and subsequent sign-ins.
- Assigns a confidence score based on various conditions, such as changes in session status, ASN (Autonomous System Number), and whether the sign-in used a browser process.
- Describes the use case based on the conditions met, such as changes in network compliance or authentication flow.
-
Summarization:
- Groups the data by initial sign-in details and aggregates subsequent sign-ins into a set.
- Sorts the results by the initial sign-in time.
In essence, this query is used to detect and analyze unusual or potentially suspicious sign-in patterns for specific applications, considering changes in network conditions, authentication methods, and session statuses.
Details

Thomas Naunheim
Released: January 2, 2026
Tables
SigninLogsAADNonInteractiveUserSignInLogsNetworkAccessTraffic
Keywords
SigninLogsAADNonInteractiveUserSignInLogsNetworkAccessTrafficUserPrincipalNameAppDisplayNameResourceDisplayNameIPAddressAutonomousSystemNumberTokenProtectionStatusSignInSessionStatusTokenTypeBrowserProcesses
Operators
letunion|where>agoin~extendiffisemptytodynamicproject-rename==joinkindleftouteronprojecttostringinnerproject-awayproject-reorder-case!=and<bag_pack_columnssummarizemake_setbysort by