from logs-o365.audit-default*
| WHERE event.dataset == "o365.audit" and event.action == "UserLoggedIn" and
source.ip is not null and o365.audit.UserId is not null and o365.audit.ApplicationId is not null and o365.audit.UserType in ("0", "2", "3", "10") and
// filter for successful logon to Microsoft Graph and from the Microsoft Authentication Broker or Visual Studio Code
o365.audit.ApplicationId in ("aebc6443-996d-45c2-90f0-388ff96faa56", "29d9ed98-a469-4536-ade2-f981bc1d605e") and
o365.audit.ObjectId in ("00000003-0000-0000-c000-000000000000")
// keep relevant fields only
| keep @timestamp, o365.audit.UserId, source.ip, o365.audit.ApplicationId, o365.audit.ObjectId, o365.audit.ExtendedProperties.RequestType, source.as.organization.name, o365.audit.ExtendedProperties.ResultStatusDetail
// case statements to track which are OAuth2 authorization request via redirect and which are related to OAuth2 code to token conversion
| eval oauth_authorize = case(o365.audit.ExtendedProperties.RequestType == "OAuth2:Authorize" and o365.audit.ExtendedProperties.ResultStatusDetail == "Redirect", o365.audit.UserId, null), oauth_token = case(o365.audit.ExtendedProperties.RequestType == "OAuth2:Token", o365.audit.UserId, null)
// split time to 30 minutes intervals
| eval target_time_window = DATE_TRUNC(30 minutes, @timestamp)
// aggregate by principal, applicationId, objectId and time window
| stats unique_ips = COUNT_DISTINCT(source.ip), source_ips = VALUES(source.ip), appIds = VALUES(o365.audit.ApplicationId), asn = values(`source.as.organization.name`), is_oauth_token = COUNT_DISTINCT(oauth_token), is_oauth_authorize = COUNT_DISTINCT(oauth_authorize) by o365.audit.UserId, target_time_window, o365.audit.ApplicationId, o365.audit.ObjectId
// filter for cases where the same appId is used by the same principal user to access the same object and from multiple addresses via OAuth2 token
| where unique_ips >= 2 and is_oauth_authorize > 0 and is_oauth_token > 0
Install detection rules in Elastic Security
Detect Suspicious Microsoft 365 UserLoggedIn via OAuth Code 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(opens in a new tab or window).