Skip to main content

Device Code Phishing: A Low-Noise, High-Impact Threat That Demands Your Attention

Introduction

In the ever-evolving landscape of cloud threats, not every adversary kicks down the front door. Some simply wait for you to open a side entrance - one designed for ease, speed, and seemingly harmless interactions. One of the most understated yet increasingly abused mechanisms is the OAuth 2.0 Device Code Flow.

Originally introduced to support input-constrained devices such as smart TVs, printers, and IoT systems, this authentication method has quietly become a high-value target for threat actors. Why? Because it provides legitimate access tokens via a flow that often lacks visibility, oversight, and adequate control mechanisms.

If you’re responsible for defending Microsoft environments, it’s time to examine the risks, detection patterns, and response strategies for device code phishing.

OAuth Device Code Flow

Threat Landscape: How Attackers Abuse Device Code Flow

The OAuth 2.0 Device Authorization Grant (RFC 8628) allows a device to obtain an access token by asking the user to authenticate via a separate device. This interaction typically involves:

  • A device_code and user_code pair
  • A login URL (https://microsoft.com/devicelogin)
  • Polling of the token endpoint until the user completes authentication

This legitimate flow becomes a vector for abuse when:

  1. An attacker requests a device code using their own client application.
  2. The attacker sends the user code and login URL to the victim via phishing (e.g., fake Teams meeting invite). In the first example is social engineering used to send a fake Teams meeting invite to the victim. The Teams information “Join the meeting” is redirecting to the device code login page and the ID is the device code. The second example is faking a sharing of a document.

3. The victim, unaware, completes the authentication on the real Microsoft login page.

4. Upon successful authentication, the access token and refresh token are issued to the attacker’s app, not the victim’s device.

Once obtained, the attacker can:

  • Access Microsoft Graph API, Outlook, Teams, OneDrive, SharePoint
  • Search for sensitive data (e.g., credentials, access links)
  • Create inbox rules, delete messages, or exfiltrate documents
  • Use Primary Refresh Tokens (PRTs) to register persistent devices

Case in Point: Threat actor Storm-2372 has been actively exploiting this method since 2024, leveraging legitimate Microsoft infrastructure to gain access across sectors including government, energy, education, and IT services.

Technical Visibility & Detection (with KQL)

Monitoring deviceCode authentications requires targeted hunting. Here are key queries and insights to surface abnormal activity:

1. Successful Device Code Sign-ins

SigninLogs 
| where TimeGenerated > ago(7d)
| where AuthenticationProtocol == "deviceCode"
| where ResultType == 0 // Successful sign-ins
| project TimeGenerated, UserPrincipalName, AppDisplayName, AppId, IPAddress,
Location, DeviceDetail, RiskLevelDuringSignIn, CorrelationId

Purpose: Establish a baseline or find any usage.

2. Timechart of Device Code Authentications by App

SigninLogs
| where TimeGenerated > ago(90d)
| where AuthenticationProtocol == "deviceCode"
| summarize count() by bin(TimeGenerated, 1d), AppDisplayName
| render timechart

Purpose: Trend analysis and app monitoring over time

3. Top Users by App & Resource

SigninLogs
| where TimeGenerated > ago(90d)
| where AuthenticationProtocol == "deviceCode"
| summarize count() by UserPrincipalName, AppDisplayName, ResourceDisplayName

Purpose: Identify legitimate use and anomalies in volume or application

4. Join Device Code Sign-ins with Device Registration Service Events

SigninLogs
| where TimeGenerated > ago(90d)
| where AuthenticationProtocol == "deviceCode"
| where ResourceDisplayName == "Device Registration Service"
| join AADNonInteractiveUserSignInLogs on $left.CorrelationId == $right.CorrelationId
| extend UserAgentNON = UserAgent1
| project UserPrincipalName, AppDisplayName, ClientAppUsed, ResourceDisplayName, UserAgent, UserAgentNON, IncomingTokenType, IncomingTokenType1

Purpose: Correlate device registrations with potentially malicious sessions

5. Unmanaged/Non-Compliant Device

SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType == 0
| where AuthenticationProtocol == "deviceCode"
| where isempty(DeviceDetail.deviceId) or DeviceDetail.isManaged == false or
DeviceDetail.isCompliant == false
| project TimeGenerated, UserPrincipalName, AppDisplayName, AppId, IPAddress,
Location, DeviceDetail, RiskLevelDuringSignIn, CorrelationId

Purpose: Find successful logins via device code from potentially risky devices. Maybe PRT elevation?

6. Microsoft Authentication Broker

SigninLogs
| where TimeGenerated > ago(7d)
| where AuthenticationProtocol == "deviceCode"
| where AppId == "29d9ed98-a469-4536-ade2-f981bc1d605e" // Microsoft Authentication Broker
| project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, Location,
DeviceDetail, RiskLevelDuringSignIn, ResultType, CorrelationId

Purpose: Detect potential PRT theft attempts.

7. User/IP Combination

let lookback = 30d;
let timeframe = 1d;
let knownUserIPs = SigninLogs
    | where TimeGenerated between (ago(lookback) .. ago(timeframe))
    | where AuthenticationProtocol == "deviceCode" and ResultType == 0
    | summarize knownIPs = make_set(IPAddress) by UserPrincipalName;
SigninLogs
| where TimeGenerated > ago(timeframe)
| where AuthenticationProtocol == "deviceCode" and ResultType == 0
| join kind=leftouter knownUserIPs on UserPrincipalName
| where isnull(knownIPs) or array_index_of(knownIPs, IPAddress) == -1
| project
    TimeGenerated,
    UserPrincipalName,
    AppDisplayName,
    AppId,
    IPAddress,
    Location,
    knownIPs,
    DeviceDetail,
    RiskLevelDuringSignIn,
    ResultType,
    CorrelationId,
    UserAgent,
    IncomingTokenType

Purpose: Identify the first time a user successfully uses device code flow from a specific IP

8. Find Phishing mail

EmailUrlInfo
| where TimeGenerated >= ago(90d)
| where Url has_any ("aka.ms/devicelogin", "microsoft.com/devicelogin", "login.microsoftonline.com/common/oauth2/deviceauth")
| project TimeGenerated, Url, NetworkMessageId, UrlLocation
| join (EmailEvents) on NetworkMessageId
| project
    TimeGenerated,
    Url,
    UrlLocation,
    Subject,
    SenderFromAddress,
    RecipientEmailAddress,
    DeliveryAction,
    DeliveryLocation

Purpose: Check if user received mail with device code login page

Indicators of Attack (IoA)

Keep an eye out for the following patterns:

  • AuthenticationProtocol == "deviceCode" from unknown or risky IPs
  • Sign-ins from unmanaged or non-compliant devices
  • Suspicious App IDs (especially generic clients like the Microsoft Authenticator Broker)
  • Mail forwarding rules or inbox rule abuse shortly after sign-in
  • Sudden deletion of large email volumes
  • Repeated login behavior involving Device Registration Service

Note: Device code authentications often bypass traditional redirect URI analysis and are challenging to flag with standard rules. Threat actors exploit this “low friction” design for persistence and stealth.

Mitigation Strategies

Control Area

Recommendation

Conditional Access

Block or restrict device code flow to approved users and applications

Token Hygiene

Regularly revoke refresh tokens for inactive or compromised sessions

App Governance

Monitor and track App IDs allowed to use device flow

User Training

Teach users to verify login prompts, avoid unsolicited meeting invites, and recognize abuse

Behavioral Analytics

Leverage Microsoft Sentinel, UEBA, and Defender XDR for anomaly detection

Warning: Blocking the flow outright may disrupt services that depend on it (e.g., some printers or compliance devices). Test and phase deployment carefully.

Action Checklist for Defender Teams

Task

Investigate use of deviceCode over the past 90 days in Sentinel and Entra logs

Correlate with suspicious App IDs and unrecognized user agents

Restrict device code flow with Conditional Access

Review token issuance and implement automated token revocation policies

Integrate custom Sentinel rules for anomalous behavior following deviceCode sign-ins

Educate your team about this attack vector and how to identify it in logs

Regularly review permissions and the registration of new devices

Bring out user information or a training to rise the awareness

 

Conclusion

Device Code Phishing is not speculative — it's active, effective, and well-documented in the wild. Unlike traditional phishing or token theft, it operates entirely within legitimate authentication flows, leveraging your existing trust in Microsoft’s infrastructure.

That’s what makes it insidious.

With the right combination of detection, conditional access, user awareness, and token management, organizations can drastically reduce their risk exposure.

Let’s not be passive observers. As defenders, it’s on us to identify, adapt, and act.

Do you have any insights or queries to share? Let's learn from each other.

References

• OAuth 2.0 device authorization grant - Microsoft identity platform | Microsoft Learn
• RFC 8628 - OAuth 2.0 Device Authorization Grant
• Device Code Phishing in Google Cloud and Azure | Huntress
• Storm-2372 conducts device code phishing campaign | Microsoft Security Blog
• Phishing for Primary Refresh Tokens and Windows Hello keys - dirkjanm.io
• Introducing a new phishing technique for compromising Office 365 accounts
• How to Detect Malicious OAuth Device Code Phishing
• Multiple Russian Threat Actors Targeting Microsoft Device Code Authentication | Volexity
• The Art of the Device Code Phish – Boku

Back to all blogs

Featured blogs