Device Code Phishing and Persistent OAuth Consent: 2026 APT Tradecraft in Entra ID
Throughout 2025 and into 2026, the cluster of activity Microsoft tracks as Storm-2372, along with APT29-aligned operators (Midnight Blizzard / Cozy Bear), has shifted decisively away from password-spray and adversary-in-the-middle MFA capture toward two cheaper, quieter primitives: the OAuth 2.0 device authorization grant (RFC 8628) and durable application consent in Entra ID. Both abuse documented protocol behavior rather than software vulnerabilities, both survive password resets, and both produce telemetry that looks indistinguishable from a legitimate user signing into Teams on a TV until you know what to filter for. For tenants that still treat “MFA enforced” as the end of the identity conversation, this is the gap.
Why this tradecraft, why now
The device code flow exists because input-constrained devices — smart TVs, IoT controllers, CLI tools on headless servers — cannot reasonably host a browser. The user is shown a short code and a URL, authenticates on a separate device, and the original client polls the token endpoint until a token is issued. Nothing about that exchange requires the polling client and the authenticating user to be on the same network, the same continent, or even the same organization. Entra ID issues the token to whichever client is polling with the matching device_code.
The operational appeal for an APT is straightforward. There is no credential to phish, no MFA prompt to intercept, no fake login page to host and burn. The victim sees a real microsoft.com URL, a real Microsoft sign-in, and a real consent screen. Conditional Access policies that key on “unmanaged device” or “untrusted location” frequently evaluate the user’s browser session, not the polling client that ultimately receives the token. Refresh tokens issued to public clients then provide weeks of access, and where the operator can also induce consent to a multi-tenant OAuth application — particularly one requesting Mail.Read, Files.Read.All, or offline_access against Microsoft Graph — the persistence outlives any password rotation, MFA re-enrollment, or session revocation that does not also touch the service principal.
What changed in 2026
Three shifts are worth calling out for SOC leads.
Consent laundering through compromised partner tenants. Rather than registering a fresh malicious multi-tenant app, operators are compromising a low-value tenant, registering the OAuth app there, and using the publisher-verified appearance of that tenant to request consent in the target. Defenders looking for newly registered apps in their own directory will not see it; the service principal materializes only when a user grants consent.
Long-tail refresh token abuse. Public-client refresh tokens in Entra ID can be redeemed for new access tokens well past the initial intrusion window, and family-of-client-IDs (FOCI) behavior allows a refresh token issued to one Microsoft first-party client to be redeemed for tokens scoped to another. Operators are deliberately seeding FOCI-eligible clients to retain access even when one client family is revoked.
Targeting of M365 Copilot and Graph connectors. Where tenants have enabled Copilot, Graph-scoped access is a force multiplier — a single compromised identity with Files.Read.All plus Copilot grounding can be queried in natural language across SharePoint, OneDrive, and Exchange Online without ever touching the file system. Treat Copilot semantic index access as a sensitive data path, not a productivity feature.
Detection: where the signal actually lives
The Entra ID sign-in logs distinguish the device code grant explicitly. Hunt on AADSignInEventsBeta (or the equivalent in your SIEM ingestion of SigninLogs) for AuthenticationProtocol == "deviceCode" and pivot on the following tells:
- Sign-ins where the user originates from a corporate egress but the resulting token is redeemed by a client IP in a hosting ASN (DigitalOcean, Hetzner, M247, residential proxy ranges) within minutes.
- Device code authentications against client IDs the tenant has no operational reason to use —
Microsoft Azure CLI,Microsoft Azure PowerShell, orVisual Studio Codefrom accounts that do not develop. - Consent grants to multi-tenant applications where the publisher tenant has fewer than ~50 service principals registered globally, or where
verifiedPublisheris null and the requested permissions includeoffline_accessplus any*.Read.AllGraph scope. - Token issuance events with
ResourceDisplayName == "Microsoft Graph"from a service principal that was first consented to within the last 30 days and has zero interactive sign-ins from any other identity.
Enable MicrosoftGraphActivityLogs (GA in 2024, broadly deployed by 2026) and join on SignInActivityId. The Graph activity log is where exfiltration actually appears — the sign-in log only tells you a token was issued.
Remediation that actually breaks persistence
Revoking sessions is not enough. The full sequence:
- Disable the user account and run
Revoke-MgUserSignInSession, then rotate the credential. - Identify every service principal the user consented to in the last 90 days via the audit log
Consent to applicationevents. For each, evaluate whether other users in the tenant also granted consent. - Remove the application’s user assignments and, where the app is not business-critical, delete the service principal outright. Deleting the app registration in the publisher tenant does not remove the service principal in yours.
- Where FOCI clients are implicated, treat all family members as compromised and revoke refresh tokens across the family, not just the originating client ID.
- Restrict the device code flow via Conditional Access (
authenticationFlowsfilter,transferMethod = deviceCodeFlow) to a named group of users with documented need. For everyone else, block it. - Move user consent for applications to admin-approval workflows. The operational cost is real; the alternative is worse.
800-53 mapping
| Control | Application |
|---|---|
| IA-2, IA-5, IA-8 | Phishing-resistant authenticators (FIDO2, certificate-based) for the populations operators target — executives, IT, finance |
| AC-2(12), AC-6(9) | Account monitoring for atypical usage; least privilege on Graph-scoped delegated permissions |
| AC-4, SC-7 | Conditional Access as policy enforcement, including authentication flow restrictions |
| AU-2, AU-6, AU-12 | Ingestion of SigninLogs, AuditLogs, and MicrosoftGraphActivityLogs with correlation, not just retention |
| CA-7 | Continuous monitoring of consented applications and service principal inventory |
| CM-7 | Disable the device code flow as a default-deny capability |
| SI-4 | Anomaly detection on token redemption locations and refresh token reuse |
| RA-5, SR-3 | Risk-rate third-party multi-tenant applications as a supply chain surface |
Bottom line
Device code phishing is not novel — it has been documented since at least 2021 — but the 2026 variant has matured into a quiet, durable persistence mechanism that bypasses most of the controls organizations actually invested in. Treat the consented service principal, not the user account, as the primary unit of compromise. If your incident response runbook ends at password reset and session revocation, it ends too early.