Azure AD Graph Access with Unusual Client and User
Description
Identifies Azure AD Graph (graph.windows.net) requests where the combination of calling OAuth client ("azure.aadgraphactivitylogs.properties.app_id") and signed-in user ("user.id") has not been observed in the tenant in a historical window. A user appearing against AAD Graph under an OAuth client that has not previously authenticated that user is a sign of a FOCI swap, a phished refresh token being redeemed for a new client, or an adversary running tooling under a client identity the user does not normally use.
Query · kuery
data_stream.dataset:"azure.aadgraphactivitylogs" and
azure.aadgraphactivitylogs.properties.actor_type : "User" and
azure.aadgraphactivitylogs.properties.app_id: (* and not (
"74658136-14ec-4630-ad9b-26e160ff0fc6" or
"bb8f18b0-9c38-48c9-a847-e1ef3af0602d" or
"00000006-0000-0ff1-ce00-000000000000" or
"18ed3507-a475-4ccb-b669-d66bc9f2a36e")
) and user.id:*
Investigation fields
Pivot points the source recommends for triage.
user.idsource.ipsource.as.organization.nameuser_agent.originalazure.aadgraphactivitylogs.properties.app_idazure.aadgraphactivitylogs.properties.api_versionurl.pathazure.tenant_id
Implementation guide
Requires Azure AD Graph Activity Logs ingested into logs-azure.aadgraphactivitylogs-* via the Elastic Azure
integration. Enable the AzureADGraphActivityLogs diagnostic-settings category on Entra ID.
Known false positives
- First-time use of a legitimate first-party or sanctioned client by the user (newly installed app, first sign-in to a workload, fresh PowerShell module install). Validate by `azure.aadgraphactivitylogs.properties.app_id` and the user's history.
- Authorized red team or audit activity. Add exceptions on the calling user after review.
Analyst notes
Investigating Azure AD Graph Access with Unusual Client and User
A (client, user) pair appearing on AAD Graph for the first time in 14 days is a high-signal indicator. Legacy AAD Graph traffic is dominated by a small set of recognised first-party callers per user; new combinations suggest one of:
- A FOCI refresh-token swap landed under a new client identity.
- The user newly consented to (or was phished into consenting to) an OAuth application.
- An adversary is using stolen tokens / credentials under a client identity the user does not normally use.
Possible investigation steps
- Identify the calling client and confirm whether the app is sanctioned.
azure.aadgraphactivitylogs.properties.app_id. Pivot to Azure portal → Enterprise Applications to check whether it is first-party, sanctioned third-party, or unfamiliar.
- Identify the user and check the surrounding auth context.
user.id, then pivot to sign-in logs (logs-azure.signinlogs-*) for the same user around the same time. Look for unusual sign-in geography, MFA bypass, or risky session signals.
- Review source posture.
user_agent.original,source.ip,source.as.organization.name. Residential / VPS / anonymising-network egress raises priority.
- Review what was queried.
url.path. Bulk recon or User-collection access via internal API versions raises triage priority.
- Check tenant-wide blast radius for the client.
- Is the same client ID hitting AAD Graph for many other users? That pattern points to large-scale consent abuse rather than a single account compromise.
- Confirm the activity is not attributable to authorized testing (red team engagement, penetration test, internal tooling validation) before treating as malicious.
Response and remediation
- Revoke refresh tokens and active sessions for the calling user.
POST /v1.0/users/{id}/revokeSignInSessions.
- Temporarily disable the user if the alert is high-confidence or you need to halt further activity while investigation continues.
PATCH /v1.0/users/{id}with body{"accountEnabled": false}.
- If the client is not a sanctioned application, revoke its OAuth consent.
GET /v1.0/oauth2PermissionGrants?$filter=clientId eq '{servicePrincipalId}', thenDELETE /v1.0/oauth2PermissionGrants/{grantId}.
- Check for device registrations created by the user during or around the burst window and remove rogue devices.
GET /v1.0/users/{id}/registeredDevicesandGET /v1.0/users/{id}/ownedDevices, thenDELETE /v1.0/devices/{deviceObjectId}.- Do this BEFORE session revocation: device-bound PRTs survive
revokeSignInSessions.
- If the calling application has no legitimate AAD Graph dependency, block further use by that app.
PATCH /beta/applications/{id}with body{"authenticationBehaviors": {"blockAzureADGraphAccess": true}}.- This property lives on the Graph beta endpoint, not v1.0.