Entra ID OAuth Device Code Flow with Concurrent Sign-ins

Last updated 13 days ago on 2026-01-21
Created 2 months ago on 2025-12-02

About

Identifies Entra ID device code authentication flows where multiple user agents are observed within the same session. This pattern is indicative of device code phishing, where an attacker's polling client (e.g., Python script) and the victim's browser both appear in the same authentication session. In legitimate device code flows, the user authenticates via browser while the requesting application polls for tokens - when these have distinctly different user agents (e.g., Python Requests vs Chrome), it may indicate the code was phished and redeemed by an attacker.
Tags
Domain: CloudDomain: IdentityData Source: AzureData Source: Entra IDData Source: Entra ID Sign-inUse Case: Identity and Access AuditUse Case: Threat DetectionTactic: Credential AccessLanguage: esql
Severity
high
Risk Score
73
MITRE ATT&CK™

Credential Access (TA0006)(external, opens in a new tab or window)

Initial Access (TA0001)(external, opens in a new tab or window)

False Positive Examples
Legitimate use of device code flow where a user authenticates via browser for a CLI tool or headless application. Common legitimate scenarios include Azure CLI, Azure PowerShell, or VS Code remote development. Review the user agent combinations - browser + known CLI tool from the same user may be expected behavior.
License
Elastic License v2(external, opens in a new tab or window)

Definition

Integration Pack
Prebuilt Security Detection Rules
Related Integrations

azure(external, opens in a new tab or window)

Query
text code block:
from logs-azure.signinlogs-* metadata _id, _version, _index | where event.category == "authentication" and event.dataset == "azure.signinlogs" and azure.signinlogs.properties.original_transfer_method == "deviceCodeFlow" // Track events with deviceCode authentication protocol (browser auth) vs polling client | eval is_device_code_auth = case(azure.signinlogs.properties.authentication_protocol == "deviceCode", 1, 0) | stats Esql.count_logon = count(*), Esql.device_code_auth_count = sum(is_device_code_auth), Esql.timestamp_values = values(@timestamp), Esql.source_ip_count_distinct = count_distinct(source.ip), Esql.user_agent_count_distinct = count_distinct(user_agent.original), Esql.user_agent_values = values(user_agent.original), Esql.authentication_protocol_values = values(azure.signinlogs.properties.authentication_protocol), Esql.azure_signinlogs_properties_client_app_values = values(azure.signinlogs.properties.app_display_name), Esql.azure_signinlogs_properties_app_id_values = values(azure.signinlogs.properties.app_id), Esql.azure_signinlogs_properties_resource_display_name_values = values(azure.signinlogs.properties.resource_display_name), Esql.azure_signinlogs_properties_auth_requirement_values = values(azure.signinlogs.properties.authentication_requirement), Esql.azure_signinlogs_properties_tenant_id = values(azure.tenant_id), Esql.azure_signinlogs_properties_status_error_code_values = values(azure.signinlogs.properties.status.error_code), Esql.message_values = values(message), Esql.azure_signinlogs_properties_resource_id_values = values(azure.signinlogs.properties.resource_id), Esql.source_ip_values = values(source.ip) by azure.signinlogs.properties.session_id, azure.signinlogs.identity // Require: 2+ events, at least one deviceCode auth protocol event, and either 2+ IPs or 2+ user agents | where Esql.count_logon >= 2 and Esql.device_code_auth_count >= 1 and (Esql.source_ip_count_distinct >= 2 or Esql.user_agent_count_distinct >= 2) | keep Esql.*, azure.signinlogs.properties.session_id, azure.signinlogs.identity

Install detection rules in Elastic Security

Detect Entra ID OAuth Device Code Flow with Concurrent Sign-ins in the Elastic Security detection engine by installing this rule into your Elastic Stack.

To setup this rule, check out the installation guide for Prebuilt Security Detection Rules(external, opens in a new tab or window).