Detecting Entra ID Token Theft and Lateral Movement in Microsoft Sentinel

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
The sign-in event for a stolen OAuth token is a successful authentication. MFA is marked as satisfied. The user agent and IP address may differ from normal, but in a cloud environment where users travel and use multiple devices, those signals alone generate too many false positives to act on. Detecting Entra ID token theft and lateral movement requires correlating multiple signals: the authentication method, token lifetime anomalies, resource access patterns, and timing relationships between events that individually appear legitimate.
Attack 1: AiTM Phishing, Stolen Session Cookies
Adversary-in-the-middle phishing works by placing an attacker-controlled proxy between the user and the legitimate Microsoft login page. The user authenticates normally, satisfies MFA, and receives a session cookie. The proxy captures that cookie and replays it from a different IP address, giving the attacker an authenticated session without triggering another MFA prompt.
The detection signal is not a failed authentication, it is an impossible travel or token replay anomaly. The attacker's session uses the same session token but from a different IP, often within seconds of the legitimate user's successful sign-in.
Sentinel KQL, AiTM session replay detection:
SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType == 0 // Successful sign-in
| where AuthenticationDetails contains "MFA"
| summarize
Sessions = make_set(SessionId),
IPs = make_set(IPAddress),
Locations = make_set(LocationDetails.city),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by UserPrincipalName, AppDisplayName
| where array_length(IPs) > 1
and datetime_diff('minute', LastSeen, FirstSeen) < 10
| project UserPrincipalName, AppDisplayName, IPs, Locations, FirstSeen, LastSeen
This surfaces users with successful MFA-satisfied sign-ins from multiple IPs within 10 minutes, the window during which an AiTM attacker replays the stolen cookie.
Attack 2: Device Code Flow Abuse
The OAuth 2.0 device code flow was designed for input-constrained devices like smart TVs. An attacker sends a phishing email asking the victim to enter a device code at microsoft.com/devicelogin, a legitimate Microsoft URL. When the victim enters the code and approves the request, the attacker receives a full OAuth token with the victim's permissions and no MFA challenge, because the user already authenticated.
Device code flow sign-ins are identifiable in Entra ID logs by their authentication method. They are legitimate in some contexts (VSCode, Azure CLI, some MDM enrollment flows) but rare enough that unexplained device code authentications warrant investigation.
Sentinel KQL, Device code authentication anomalies:
SigninLogs
| where TimeGenerated > ago(7d)
| where AuthenticationProtocol == "deviceCode"
| where ResultType == 0
| summarize
DeviceCodeSignIns = count(),
Apps = make_set(AppDisplayName),
IPs = make_set(IPAddress)
by UserPrincipalName
| where DeviceCodeSignIns > 0
// Exclude known legitimate device code users (VSCode, Azure CLI)
| where not(Apps has "Visual Studio Code" or Apps has "Microsoft Azure CLI")
| sort by DeviceCodeSignIns desc
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Attack 3: Primary Refresh Token Extraction
The Primary Refresh Token (PRT) is a long-lived credential stored on Entra ID-joined or registered Windows devices that provides seamless SSO across all Microsoft services. An attacker with code execution on a developer machine can extract the PRT using tools like ROADtoken or AADInternals and use it from a different machine to authenticate as the victim to any Entra-integrated application without triggering MFA.
PRT theft is detected by looking for authentication from Entra-joined devices using a PRT where the device ID does not match the device normally used by that user, or where the same PRT claim appears in sign-ins from geographically inconsistent locations.
Sentinel KQL, PRT authentication from unexpected devices:
SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType == 0
| where AuthenticationDetails has "PrimaryRefreshToken"
| summarize
Devices = make_set(DeviceDetail.deviceId),
IPs = make_set(IPAddress),
OS = make_set(DeviceDetail.operatingSystem)
by UserPrincipalName
| extend DeviceCount = array_length(Devices)
| where DeviceCount > 2 // Alert on PRT use from more than 2 devices
| project UserPrincipalName, DeviceCount, Devices, IPs
| sort by DeviceCount desc
Attack 4: OAuth App Consent Phishing
Consent phishing tricks users into granting a malicious OAuth application access to their mailbox, OneDrive, or calendar. The malicious app is registered in a different tenant but requests delegated permissions via the standard OAuth consent flow. After consent, the attacker has persistent access that survives password resets and MFA changes, because the token belongs to the app, not to the user's session.
Detect consent to applications from external tenants, especially applications requesting high-privilege permissions (Mail.ReadWrite, Files.ReadWrite.All, User.Read.All).
Sentinel KQL, High-privilege consent grants to external apps:
AuditLogs
| where TimeGenerated > ago(7d)
| where OperationName == "Consent to application"
| where Result == "success"
| extend
AppName = tostring(TargetResources[0].displayName),
AppId = tostring(TargetResources[0].id),
GrantedPermissions = tostring(AdditionalDetails)
| where GrantedPermissions has_any (
"Mail.ReadWrite", "Files.ReadWrite.All",
"User.Read.All", "Calendars.ReadWrite"
)
| project
TimeGenerated,
InitiatedBy = InitiatedBy.user.userPrincipalName,
AppName,
GrantedPermissions
| sort by TimeGenerated desc
Attack 5: Cross-Tenant Lateral Movement via B2B
Organizations that configure Entra ID B2B cross-tenant access to allow partner or customer access may inadvertently create lateral movement paths. An attacker who compromises a user in a partner tenant can access your tenant's resources via B2B trust, appearing in your logs as an external guest with a legitimate token from the partner tenant.
Detect unusual cross-tenant access patterns, external principals accessing resources they have not historically accessed, or accessing resources outside their normal business hours.
Sentinel KQL, External tenant access anomalies:
SigninLogs
| where TimeGenerated > ago(7d)
| where HomeTenantId != ResourceTenantId // Cross-tenant sign-in
| where ResultType == 0
| summarize
AccessCount = count(),
Resources = make_set(ResourceDisplayName),
FirstSeen = min(TimeGenerated)
by UserPrincipalName, HomeTenantId
| where AccessCount > 10 // Active cross-tenant users
| join kind=leftouter (
// Compare to 30-day historical baseline
SigninLogs
| where TimeGenerated between (ago(37d) .. ago(7d))
| where HomeTenantId != ResourceTenantId
| summarize HistoricalCount = count() by UserPrincipalName
) on UserPrincipalName
| where isempty(HistoricalCount) // No historical cross-tenant activity
| project UserPrincipalName, HomeTenantId, AccessCount, Resources, FirstSeen
Building a Baseline and Reducing False Positives
The queries above will generate false positives in any environment with legitimate device code use, frequent travel, or active B2B partnerships. Reduce noise by:
Building named location exclusions: Add your corporate office IP ranges and known VPN exit IPs as Named Locations in Entra ID. Exclude these from impossible travel detections, the signal you want is authentication from residential IPs, cloud hosting ranges, or countries where you have no employees.
Allowlisting known-good device code apps: Maintain a list of legitimate device code applications in your environment (Azure CLI, VSCode, Intune enrollment). Exclude these from device code detection alerts. Alert on all others.
Correlating with risky sign-in events: Entra ID Identity Protection already flags some of these patterns as risky sign-ins. In Sentinel, join SigninLogs against AADRiskySignIns to avoid duplicating detection work:
SigninLogs
| join kind=inner AADRiskySignIns on $left.CorrelationId == $right.CorrelationId
| where RiskLevelDuringSignIn in ("high", "medium")
The bottom line
Entra ID token theft does not look like a brute-force attack in your logs, it looks like a successful sign-in from an unusual location. The detection requires correlating authentication method, device history, token replay timing, and permission scope across multiple log sources. The KQL queries in this guide surface the behavioral anomalies that distinguish legitimate cloud access from stolen credential use.
Frequently asked questions
What is the difference between a session token and a Primary Refresh Token in Entra ID?
A session token is a short-lived cookie that grants access to a specific application for a limited time (typically 1 hour). A Primary Refresh Token (PRT) is a long-lived credential (valid for up to 90 days, renewable) stored on an Entra-joined device that can be used to silently obtain new access tokens for any Entra-integrated application without re-authentication.
Does Conditional Access prevent token theft attacks?
Partially. Conditional Access Token Protection (in preview as of 2024) binds tokens to the specific device that obtained them, preventing replay from other devices. Without Token Protection, Conditional Access policies evaluate the initial authentication but cannot prevent a stolen token from being replayed within its validity window.
How do I detect AiTM phishing before the token is used?
The pre-use detection is in email security, AiTM phishing kits like Evilginx2 and Modlishka have known infrastructure patterns and phishing page structures. Microsoft Defender for Office 365 and third-party email security tools detect many AiTM lure emails. After the token is stolen, the only detection is the replay anomaly in sign-in logs.
What should I investigate first when an Entra ID token theft alert fires?
Check what the stolen token accessed: in Sentinel, query SigninLogs and AuditLogs for all activity by the affected user in the 4 hours after the anomalous sign-in. Look for mailbox rule creation (common for email exfiltration), OAuth app consent grants, role assignments, and access to sensitive SharePoint/OneDrive files.
Can I revoke a stolen OAuth token?
Yes. Use Revoke-AzureADUserAllRefreshToken (PowerShell) or the revokeSignInSessions Graph API endpoint. This invalidates all refresh tokens for the user, forcing re-authentication on all devices and applications. It does not immediately invalidate access tokens already issued, those remain valid until their expiry (typically 1 hour). Change the user's password and require MFA re-registration in parallel.
How do I tune the Sentinel KQL queries in this guide to reduce false positives from legitimate users who frequently travel or work across multiple devices?
Build a named entity table of high-travel users (executives, sales, field engineers) and join it into each query as an exclusion or a separate lower-severity alert tier. For device-count anomalies in the PRT detection query, calculate a per-user historical device count baseline from the prior 90 days and alert only when the current count exceeds that user's own baseline by more than one device -- this avoids flagging a developer who legitimately uses four machines. For impossible travel detection, add a speed-of-travel threshold calculation: divide the geographic distance between consecutive sign-in locations by the elapsed time, and alert only when the implied travel speed exceeds 900 km/h (roughly impossible without a private jet). Store the baseline data as a Sentinel watchlist updated weekly by a scheduled Logic App that queries SigninLogs, so the baselines automatically adapt to behavioral changes without manual tuning.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
