Home / Blog / Alert Triage

Intermediate Alert Triage

How to Triage Device Code Phishing Alerts in Microsoft Entra ID

A hands-on triage guide for device code sign-ins in Entra ID: separate real use from phishing, check for token abuse and device registration, then contain the account.

Device code phishing gets a user to complete a genuine Microsoft sign-in, including MFA, on behalf of an attacker. The login page is real and the password never leaves the user's hands, so many of the usual phishing checks come back clean. This guide helps analysts who work Entra ID alerts decide quickly whether a device code sign-in is harmless, suspicious or an active compromise.

You will needEntra sign-in and audit logs, ideally in Sentinel or Splunk
Main signalAuthentication protocol set to deviceCode
ATT&CKT1566.002, T1528, T1098.005, T1078.004
>

Scenario: Your SIEM raises "First device code authentication for user" on j.smith@example.com, a finance manager. The sign-in succeeded and MFA was satisfied. The source IP, 203.0.113.50, is not one you have seen for this user. Twenty minutes earlier, she received a Teams meeting invitation from an external sender. You need to decide whether this is a real incident before the attacker has time to dig in.

How does the attack work?

The device code flow exists for devices with limited input, such as shared screens and digital signage. A device shows a short code, and the user types it into a browser on another device to approve the sign-in. Microsoft describes the flow as high risk and recommends blocking it wherever possible.

Attackers abuse the separation between the device asking for access and the person approving it. The victim authenticates on the real Microsoft page, but the resulting tokens go to the client that started the flow, which the attacker controls.

1 Attacker gets a code Client requests a device code 2 Lure delivers it Fake meeting invite or file share 3 Victim approves Real sign-in page, real MFA 4 Tokens issued Sent to the attacker's client
The victim's sign-in is genuine. Only the recipient of the tokens is wrong.

This is not only theoretical. Microsoft reported a device code campaign by Storm-2372, active since August 2024, using lures that resembled Microsoft Teams meeting invitations. Microsoft later reported the group moving to the client ID for Microsoft Authentication Broker, which could let it register a device in Entra ID and obtain a Primary Refresh Token (PRT).

Find every device code sign-in

Start by pulling all device code activity for the user and the wider tenant. Include the non-interactive table. Sessions started with device code stay protocol tracked through later token refreshes, so much of the follow-on activity can sit there.

Microsoft Sentinel

Microsoft SentinelKQL
union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(7d)
| where AuthenticationProtocol =~ "deviceCode"
    or OriginalTransferMethod in~ ("deviceCodeFlow", "Device code flow")
| project TimeGenerated, Type, UserPrincipalName, AppDisplayName, AppId,
    ResourceDisplayName, IPAddress, Location, UserAgent, ResultType,
    ConditionalAccessStatus, CorrelationId, SessionId
| sort by TimeGenerated desc
!

Watch out: If your workspace does not ingest AADNonInteractiveUserSignInLogs, the query above still runs but can hide most of the token activity. Check this before you trust a clean result. The stored value of OriginalTransferMethod can also differ between sources, so confirm how it appears in your own tenant.

Splunk

This version assumes Entra logs arrive with the azure:monitor:aad sourcetype. Change the index and sourcetype to match your environment.

SplunkSPL
index=azure sourcetype="azure:monitor:aad"
    category IN ("SignInLogs", "NonInteractiveUserSignInLogs")
    "properties.authenticationProtocol"=deviceCode
| rename properties.* as *
| stats count min(_time) as firstTime max(_time) as lastTime
    values(ipAddress) as src_ips values(appDisplayName) as apps
    values(resourceDisplayName) as resources values(userAgent) as user_agents
    by userPrincipalName
| sort - lastTime
| convert ctime(firstTime) ctime(lastTime)

Is this device code use expected?

Device code has legitimate users. Administrators may use it with command line tools, and meeting room or shared devices may rely on it. Establish a 30 day baseline so you can tell routine use from a one-off event.

Microsoft SentinelKQL
union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(30d)
| where AuthenticationProtocol =~ "deviceCode"
| summarize SignIns = count(), Users = dcount(UserPrincipalName),
    IPs = dcount(IPAddress), FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by AppDisplayName, AppId
| sort by Users asc

Then answer these questions for the alert in front of you:

  • Does this user's role explain device code? An engineer using a command line tool differs from a finance manager with no such need.
  • Is the client one you expect? Check AppId against your approved list. Microsoft Authentication Broker (29d9ed98-a469-4536-ade2-f981bc1d605e) deserves extra attention, especially alongside a new device registration.
  • Does the source IP match the user's known locations, VPN egress or corporate range?
  • Did a suspicious invitation, shared file notice or chat message arrive shortly beforehand?
  • Can the user confirm they typed a code, and why? Ask through a trusted channel, not the possibly compromised mailbox or Teams account.
+

Tip: Ask the user a neutral question such as "Did anyone ask you to enter a code on a Microsoft page today?" Many victims believe they were simply joining a meeting, so "Did you approve a suspicious sign-in?" can get an honest but misleading no.

Trace the lure

If you have Defender for Office 365, look for clicks that passed through Microsoft's device login pages. A click there, close to the sign-in, links the email to the authentication.

Defender XDR advanced huntingKQL
UrlClickEvents
| where Timestamp > ago(7d)
| where UrlChain has_any ("microsoft.com/devicelogin",
    "login.microsoftonline.com/common/oauth2/deviceauth")
| join kind=leftouter (
    EmailEvents
    | distinct NetworkMessageId, Subject, SenderFromAddress
    ) on NetworkMessageId
| project Timestamp, AccountUpn, Subject, SenderFromAddress, Url, UrlChain,
    ActionType, IsClickedThrough
| sort by Timestamp desc

A missing click does not clear the user. The lure may have arrived through Teams or a personal device, or the user may have typed the address by hand. If you do find the message, search for other recipients, because one lure often goes to several people.

i

Note: Microsoft's published hunting for this campaign also looks for error code 50199 followed by a success in the same session, which can reflect the pause while a user enters the code. Treat that as supporting evidence only, because the pattern alone does not prove phishing.

Check what happened after sign-in

Now work out what the token was used for. Build a timeline for the user, starting shortly before the alert. Look for new IP addresses, new user agents and resources the user does not normally touch.

Microsoft SentinelKQL
let upn = "j.smith@example.com";
union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(3d)
| where UserPrincipalName =~ upn
| summarize Events = count(), FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by IPAddress, Location, AppDisplayName, ResourceDisplayName,
    AuthenticationProtocol, OriginalTransferMethod, UserAgent
| sort by FirstSeen asc

Next, check for device registration. This matters because a device registered by the attacker can keep access going after the original tokens are dealt with.

Microsoft SentinelKQL
let upn = "j.smith@example.com";
AuditLogs
| where TimeGenerated > ago(7d)
| where OperationName in ("Register device", "Add device",
    "Add registered owner to device", "Add registered users to device")
| where tostring(InitiatedBy) has upn or tostring(TargetResources) has upn
| project TimeGenerated, OperationName, Result, InitiatedBy, TargetResources
| sort by TimeGenerated desc

Weigh what you find using the cards below.

Device registered soon after sign-in

High
Indicator

A device code sign-in using Microsoft Authentication Broker, followed closely by a new device and a new registered owner.

Response

Treat as confirmed compromise. Disable the device object and look for PRT activity from it.

Mailbox or file access from a new source

High
Indicator

Non-interactive sign-ins to Exchange, SharePoint or Microsoft Graph from the same unfamiliar IP or user agent.

Response

Contain the account, then review mail access, inbox rules and file downloads.

Failed or blocked attempt

Medium
Indicator

Device code attempts ended in failure, or Conditional Access blocked them, with no successful session afterwards.

Response

Check whether the user received a lure and whether colleagues were targeted. Close only when no success exists in either sign-in table.

Decide how far to escalate

Use a simple ladder so the decision stays consistent between shifts. Your own playbook takes priority where it differs.

  1. L0
    Expected useKnown user, approved client, known location and a confirmed reason. Document it and tune if it recurs.
    Close
  2. L1
    Unexplained sign-inThe user cannot explain it, or the source looks odd, but you see no token abuse yet. Contact the user and keep investigating.
    Investigate
  3. L2
    Confirmed phishingA lure is linked to the sign-in, or the user confirms entering a code. Revoke sessions and search for other recipients.
    Contain
  4. L3
    Persistence or data accessA rogue device, mailbox access, new MFA methods or privileged activity. Declare an incident and engage incident response.
    Incident

Contain the account

A password reset on its own does not address this attack, because the attacker holds tokens rather than a password. Follow your playbook, and make sure these steps are covered:

  1. Revoke the user's sessions. This invalidates refresh tokens and session cookies.
  2. Disable any device the attacker registered. Keep its details as evidence before removing it.
  3. Review recently added MFA methods, application consents, inbox rules and forwarding.
  4. Keep watching sign-ins until any access tokens issued before the revocation have expired.
  5. Search for the same lure, sender and source IP across other users.
Microsoft Graph PowerShellPowerShell
Connect-MgGraph -Scopes "User.RevokeSessions.All"
Revoke-MgUserSignInSession -UserId "j.smith@example.com"
!

Watch out: Revoking sessions does not instantly kill an access token that has already been issued. It can stay valid until it expires, unless Continuous Access Evaluation applies. Revocation also does not remove rogue devices, consent grants or mailbox rules, so check each one separately.

Reduce the risk for next time

Once the incident is closed, pass the findings to whoever owns identity controls. The strongest fix is a Conditional Access policy that blocks device code flow, with tightly scoped exceptions.

  • Create the policy under Conditions, Authentication Flows, and select Device code flow with a Block access grant.
  • Exclude your emergency access accounts, then run in report-only mode and use the results to identify genuine users.
  • Allow only documented exceptions, restricted by user, device or location where possible.
  • Review who can register devices in Entra ID and whether enrolment restrictions fit your needs.
  • Send AADNonInteractiveUserSignInLogs to your SIEM so the follow-on activity is visible.
i

Note: After the policy goes live, protocol tracking may block sessions that started with device code, even when a later request uses a different flow. Error AADSTS530036 can appear in this case. Tell your service desk in advance so they can recognise it.

Key takeaways

  1. Device code phishing uses the real Microsoft login page and real MFA, so a clean login page does not rule it out.
  2. Search both interactive and non-interactive sign-in logs, and confirm that the non-interactive table is actually ingested.
  3. Judge each sign-in on user role, client, source IP, recent lures and what the user says happened.
  4. Treat a device registration soon after a device code sign-in as a serious sign of persistence.
  5. Revoke sessions and check devices, MFA methods, consents and mail rules. A password reset alone is not enough.
  6. Recommend blocking device code flow through Conditional Access, starting in report-only mode.

Save the queries from this guide in your SIEM with your tenant's table names and approved client list already filled in. The next time this alert fires, you will spend your time on the decision instead of rebuilding the search.

Keep going

More in Alert Triage