OAuth’s Device Authorization Grant (RFC 8628) was designed for TVs, CLIs, and IoT devices that can’t open a browser. Unfortunately, attackers have turned it into one of the most effective MFA-bypass techniques of 2024–2026, targeting thousands of Microsoft 365 organizations per campaign. This guide explains how the attack works at the protocol level and gives you specific, actionable steps to block it in every major identity platform.
How Device Code Phishing Works (Protocol-Level)
The Device Authorization Grant flow involves three parties: the device (attacker’s script), the authorization server (Microsoft, your IdP), and the user. Here’s the normal flow — and where attackers hijack it:
Legitimate flow:
- Device calls
/oauth2/v2.0/devicecode→ receivesdevice_code,user_code, andverification_uri - Device polls
/oauth2/v2.0/token?grant_type=urn:ietf:params:oauth:grant-type:device_code - User visits
https://microsoft.com/devicelogin, enters the code, authenticates - Device receives access token + refresh token
Attacker’s flow:
- Attacker runs SquarePhish, Graphish, or a custom script to request a fresh
device_code + user_code - Attacker sends a spear-phishing email to the target: “Your Microsoft account requires device verification. Visit [legitimate Microsoft URL] and enter code: ABCD-1234”
- Target enters the code and authenticates — including completing MFA
- Attacker’s polling script receives a fully authorized refresh token (valid 90 days by default)
- Attacker uses the refresh token to access Exchange, Teams, SharePoint, OneDrive
Why MFA doesn’t stop it: The user completes MFA against the legitimate Microsoft login page. The user is the one granting consent — they just don’t realize they’re authorizing an attacker’s application session.
Why it’s hard to detect: The attacker’s token request comes from a Microsoft IP range (via device_code polling against login.microsoftonline.com). The initial phishing step may use only email, not a phishing site.
Mitigation 1: Disable Device Code Flow in Microsoft Entra ID
The most effective mitigation is blocking device code flow entirely for users who don’t legitimately need it (almost everyone).
Conditional Access Policy (Recommended)
Important: Exclude accounts that genuinely need device code (service TV accounts, lab testing). Assign to a separate group and exempt them.
Using PowerShell (Microsoft Graph)
# Install module if needed: Install-Module Microsoft.Graph
Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess"
$policy = @{
displayName = "Block Device Code Flow"
state = "enabled"
conditions = @{
users = @{ includeUsers = @("All") }
applications = @{ includeApplications = @("All") }
authenticationFlows = @{ transferMethods = "deviceCodeFlow" }
}
grantControls = @{
operator = "OR"
builtInControls = @("block")
}
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $policy
Authentication Methods Policy (Tenant-Wide)
For tenants without Entra P1/P2 (no Conditional Access), you can restrict device code via the Authentication Flows policy:
# GET current policy
GET https://graph.microsoft.com/beta/policies/authenticationFlowsPolicy
# PATCH to disable device code
PATCH https://graph.microsoft.com/beta/policies/authenticationFlowsPolicy
{
"selfServiceSignUp": {
"isEnabled": false
}
}
Note: Full device code suppression via Graph API requires Policy.ReadWrite.AuthenticationFlows scope.
Mitigation 2: Disable Device Code Grant in Keycloak
Keycloak enables Device Authorization Grant per-client. If you’re using Keycloak as a federation proxy for M365/Entra, disable it at the realm and client level.
Disable at Realm Level (Keycloak 21+)
Or via REST API:
# Get realm settings
curl -s -H "Authorization: Bearer $TOKEN" \
"https://keycloak.example.com/admin/realms/your-realm" | \
python3 -m json.tool | grep "oauth2Device"
# Disable device authorization grant
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"oauth2DeviceAuthorizationGrantEnabled": false}' \
"https://keycloak.example.com/admin/realms/your-realm"
Disable Per-Client
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"attributes": {
"oauth2.device.authorization.grant.enabled": "false"
}
}' \
"https://keycloak.example.com/admin/realms/your-realm/clients/{client-uuid}"
Verify the Endpoint is Blocked
# Should return 400 or 404 after disabling
curl -X POST "https://keycloak.example.com/realms/your-realm/protocol/openid-connect/auth/device" \
-d "client_id=test-client"
# Expected: {"error":"not_supported","error_description":"..."}
Mitigation 3: Disable Device Code Grant in Auth0
In Auth0, the Device Authorization Flow is a grant type enabled per-application.
Via Auth0 Dashboard
Via Auth0 Management API
# List current grant types
curl -s -H "Authorization: Bearer $MGMT_TOKEN" \
"https://YOUR_DOMAIN.auth0.com/api/v2/clients/$CLIENT_ID" | \
jq '.grant_types'
# Remove device_code from grant types
curl -X PATCH \
-H "Authorization: Bearer $MGMT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"grant_types": ["authorization_code", "refresh_token", "client_credentials"]
}' \
"https://YOUR_DOMAIN.auth0.com/api/v2/clients/$CLIENT_ID"
Tenant-Level Lockdown
For Auth0 Enterprise, you can disable the grant at the tenant level by removing it from the allowlist in the Tenant Settings → Advanced → Grant Types.
Detection: SIEM Rules for Device Code Phishing
Disabling device code is the best fix. If you can’t disable it immediately, add detection:
Microsoft Sentinel (KQL)
// Detect device code authentication that deviates from normal CLI/device sources
SigninLogs
| where AuthenticationProtocol == "deviceCode"
| where ResultType == "0" // Successful auth
| where DeviceDetail.operatingSystem !in ("Windows", "macOS", "Linux") // Unexpected OS
or ClientAppUsed == "Mobile Apps and Desktop clients" // Unusual client
| project TimeGenerated, UserPrincipalName, IPAddress,
DeviceDetail, AppDisplayName, Location
| order by TimeGenerated desc
// Alert: Device code auth from same user_code polled from multiple IPs
// (indicates attacker polling from different IP than user login)
SigninLogs
| where AuthenticationProtocol == "deviceCode"
| where ResultType == "0"
| summarize IPList = make_set(IPAddress), Count = count()
by UserPrincipalName, bin(TimeGenerated, 1h)
| where Count > 2 and array_length(IPList) > 1
Splunk (SPL)
index=azure_ad sourcetype=azure:aad:signin
AuthenticationProtocol=deviceCode
ResultType=0
| stats count by UserPrincipalName, IPAddress, AppDisplayName, DeviceOperatingSystem
| where count > 1 AND (DeviceOperatingSystem="Unknown" OR DeviceOperatingSystem="")
| table _time, UserPrincipalName, IPAddress, AppDisplayName, DeviceOperatingSystem
Audit Log Indicators
Look for these patterns in Entra ID / Unified Audit Log:
Operation: UserLoginFailedwithErrorCode: AADSTS70019(device code expired — attacker is requesting many codes hoping one gets used)Operation: Sign-in+AuthenticationProtocol: deviceCodefrom known VPN exit IPs or anonymizers- User logs in via device code, then immediately accesses Exchange or SharePoint from a different IP than their normal workstation
Response Playbook: If Device Code Phishing Succeeded
If a user’s M365 account was compromised via device code phishing:
# 1. Revoke all refresh tokens for the user
Revoke-MgUserSignInSession -UserId "[email protected]"
# 2. Reset the user's password (forces new authentication)
Update-MgUser -UserId "[email protected]" -PasswordProfile @{
ForceChangePasswordNextSignIn = $true
Password = "TempPass!$(Get-Random)"
}
# 3. Revoke all OAuth app consents (Microsoft Graph)
# GET delegated permission grants
GET https://graph.microsoft.com/v1.0/users/{userId}/oauth2PermissionGrants
# DELETE specific grant
DELETE https://graph.microsoft.com/v1.0/oauth2PermissionGrants/{id}
# 4. Review mail rules (attackers often create inbox rules to forward email)
Get-InboxRule -Mailbox "[email protected]"
# 5. Check MFA registrations (attackers may add their own MFA method)
GET https://graph.microsoft.com/v1.0/users/{userId}/authentication/methods
FAQ
Q: Does disabling device code flow in Entra ID break legitimate TV/IoT apps?
Yes, if those apps use the device authorization grant. Exclude them from the Conditional Access policy using a named group (e.g., “Device Code Exempt Accounts”). Only service accounts used by TVs or kiosk devices should be in this group, never regular user accounts.
Q: Our users regularly use Azure CLI — does az login use device code?
az login defaults to browser-based authentication on machines with a browser. Device code is used when you run az login --use-device-code explicitly or when running in a headless environment. Your policy should allow device code for your DevOps service accounts but block it for all standard users.
Q: Can attackers use device code phishing against non-Microsoft IdPs?
Yes — any IdP that implements RFC 8628 is potentially vulnerable if users can be socially engineered to enter a code on the legitimate authorization server. Okta, Google Workspace, and Ping Identity all support device code. Defense is the same: disable it or restrict it to specific client IDs.
Q: How do I detect if my tenant has already been compromised?
Run this KQL query against the last 90 days (refresh token lifetime) in Microsoft Sentinel:
SigninLogs
| where TimeGenerated > ago(90d)
| where AuthenticationProtocol == "deviceCode"
| where ResultType == "0"
| summarize DeviceCodeLogins = count() by UserPrincipalName
| order by DeviceCodeLogins desc
Any user with device code logins who doesn’t operate a TV or CLI service warrants investigation.
Q: Will blocking device code break the mstsc /remotepc Remote Desktop flow?
No. Remote Desktop uses a separate authentication flow (MS-RDPBCGR), not device authorization grant. Blocking device code does not affect RDP, Windows Hello, or SSPR.
Internal Linking
For the broader category of non-human identity threats that device code phishing enables (service account compromise, long-lived refresh tokens), see NHI Secrets Sprawl: Fixing the Non-Human Identity Credential Crisis.
For news coverage of active device code phishing campaigns against M365 organizations, see Device Code Phishing Campaign Targets 340+ Microsoft 365 Organizations.
For MFA bypass techniques that pair with device code phishing in layered attack chains, see MFA Bypass Attacks: Understanding Threats and Implementing Phishing-Resistant Authentication.

