Skip to main content

AzureAD (Entra ID) Audit

The Azure Directory Audit template collects the Microsoft Entra ID (formerly Azure AD) directory audit log from Microsoft Graph: users and groups created or modified, role assignments, application registrations and consent grants, password resets, and privileged identity management activity. It is the record of what changed in your identity system and who changed it.

Like Office 365 Activity API and Office 365 Resource Watch, it is authorised by administrator consent: you supply one administrator's email address and Microsoft asks that administrator to approve a Fluency application that already exists. You never open the Microsoft portal, and the person who finishes the setup may not be you.

The setup has two halves, in the opposite order to most guides:

  1. In Fluency — install the Azure Directory Audit template with an administrator's email address. This sends the approval request.
  2. In Microsoft — that administrator reviews the permissions and accepts.

Which of the four Microsoft 365 pages you want

Azure Directory Audit
(this page)
Office365Office365 Resource WatchOffice365-Audit
GuideThis pageActivity APIResource WatchOffice 365 Audit
CollectsEntra directory auditThe unified audit logTenant resource inventoryAll three
Default authenticationAdministrator consentAdministrator consentAdministrator consentClient secret only
What you supplyAn admin's email addressAn admin's email addressAn admin's email addressTenant ID, client ID, client secret
Lands inIndex AzureAuditIndex Office365SIEM → ResourcesBoth indexes and Resources
Entra applicationFluencyAzureADAuditFluency Office365 Event ReaderFluencyOffice365ResourceWatchOne you register yourself

Each of the three consent templates is a separate application in Microsoft Entra ID with its own permission set, so consenting to one does not consent to the others.

This template and Office365-Audit cannot both run at their defaults

Both write to a data-lake index named AzureAudit — it is this template's datalake index name and the datalake index name for AzureAudit on Office365-Audit. Two applications writing to the same index name in the same lake will collide, and the second one aborts. Change the name on whichever you install second, or uninstall the other first.

This is not the same data as Audit.AzureActiveDirectory in the unified log

Office 365 Activity API also carries Entra activity, through the unified audit log's Audit.AzureActiveDirectory content type. The two overlap in coverage and are not the same records: this page's feed is the Entra directory audit read directly from Microsoft Graph, and that one is Entra activity as Microsoft 365 rewrites it into the unified log — different shapes, different fields, and different retention rules.

Microsoft states the separation plainly: "Microsoft Entra ID audit and sign-in logs are separate from the Microsoft 365 Unified Audit Log (UAL). UAL retention is managed through Microsoft Purview Audit and is not affected by Microsoft Entra ID licensing changes."

Running both is reasonable — it is duplicate coverage, not duplicate data. Running neither, on a tenant that has Office 365, is the mistake.

What arrives

Events land in the data-lake index named on the install form, AzureAudit by default.

StreamEndpointPermissionContents
Directory auditGET /v1.0/auditLogs/directoryAuditsAuditLog.Read.AllDirectory changes: users and groups created or modified, role assignments, application and consent grants, password resets, PIM activity.
Sign-insGET /v1.0/auditLogs/signInsAuditLog.Read.AllInteractive sign-ins with client IP, device, application, conditional-access result and risk state. Premium-only — see Before you begin.
If sign-in telemetry is what you are after, check where it lands

The consented permission covers both endpoints, but Azure Directory Audit exposes a single datalake index name, where Office365-Audit creates a separate AzureSigninLogs index for sign-ins. If sign-ins are the reason you are installing this, Office 365 Audit documents that index explicitly and is the surer route.

To see which indexes your install created here, open the application's details panel with the blue eye button and read its Actions list.

Retention is the shortest of any Microsoft feed, and it is unforgiving

ReportEntra ID FreeEntra ID P1Entra ID P2
Audit logsSeven days30 days30 days
Sign-insSeven days30 days30 days

Seven days on a Free tenant is the number that catches people. A collection outage over a long weekend, unnoticed until Tuesday, is close to the limit; anything longer is permanent loss. Microsoft is explicit that there is no recovery path: "Log retention changes aren't retroactive", and "Data that has already expired can't be recovered unless it was previously archived."

Upgrading the licence does not help after the fact either — "Azure stores up to seven days of activity data for a free version. When you switch from a free to a premium version, you can only see up to 7 days of data."

The practical consequence for this integration: treat a broken collection here as more urgent than a broken collection anywhere else in this category. The unified audit log gives you seven days of API reach over 180 days of retention, so a gap there is at least recoverable by export. Here, once it ages out of Entra, it is gone from Microsoft too.

Before you begin

A Global Administrator or Privileged Role Administrator. Microsoft's rule is:

Privileged Role Administrator, for granting consent for apps requesting any permission, for any API.

Cloud Application Administrator, AI Administrator, or Application Administrator, for granting consent for apps requesting any permission for any API, except Microsoft Graph app roles (application permissions).

This application requests AuditLog.Read.All as a Microsoft Graph application permission — the consent screen shows "Read all audit log data", which is unambiguously the app-only variant, since the delegated one reads "Read audit log data". That puts it in the exception, so Cloud Application Administrator and Application Administrator are not sufficient. Send the request to a Global Administrator or a Privileged Role Administrator.

Microsoft Entra ID P1 or P2, but only for sign-ins.

The licence gate applies to sign-ins, not to the directory audit

An earlier version of this page said a P1 or P2 licence was required for the integration as a whole, citing Microsoft's Microsoft Graph activity logs documentation. That is a different API — a log of Graph API requests — and the requirement does not transfer.

The directory audit works on every tier, including Free, at seven days' retention. Only the sign-in endpoint is premium-gated: without P1 or P2 it returns

Authentication_RequestFromNonPremiumTenantOrB2CTenant:
Neither tenant is B2C or tenant doesn't have premium license

and the rest of the integration is unaffected. Do not let a Free tenant stop you installing this.

No tenant switch to turn on. Unlike the unified audit log, the directory audit needs nothing enabled first — Entra records it without being asked, and Microsoft notes that "Entries in the audit logs are system generated and can't be changed or deleted." Retention, however, can be extended beyond the defaults below by routing the logs to an Azure storage account with Azure Monitor, which is worth knowing if the seven-day window is the problem you are trying to solve.

The address you supply has to be a working mailbox that the approver reads.

Access to the Fluency portal with permission to install applications.

Part 1 — Fluency

Install the Application

Go to Platform → Applications → Install Application From Template and choose Azure Directory Audit from the Office Software (SaaS) and IAM category.

ParameterNotes
Enable Admin Consent Mode?Checkbox, ticked by default. Leave it ticked for the route this page documents. Unticking it changes the form — see If your tenant will not allow the consent route.
admin email addressThe administrator who will be asked to approve. Must be a mailbox they actually read, and must belong to a Global Administrator or Privileged Role Administrator.
datalakePre-filled managed.
datalake index namePre-filled AzureAudit. Two applications writing to the same index name in the same lake will collide, and the second one aborts.

Setup New Azure Directory Audit Application panel with Enable Admin Consent Mode ticked, an admin email address field, and a datalake index name of AzureAudit

Press Install. The application then appears in the Installed Applications view, where its badge reads Running once the pipeline is up.

Running does not mean working — it means waiting

The badge reflects the pipeline, not the consent. Until the administrator approves in Microsoft, this application is a correctly-built pipeline with nothing to read, and it looks identical to one that is collecting normally. There is no "waiting for approval" state to watch for, so the check that answers the question is on the Microsoft side — see Confirm it is running.

Given seven-day retention on a Free tenant, an approval that sits unread for a fortnight is not just a delayed install. It is two weeks of directory audit that no longer exists anywhere.

If your organisation blocks consent to third-party applications, untick Enable Admin Consent Mode — the form replaces the email field with Azure Tenant ID, Azure ClientID and Azure ClientSecret, for an app registration you create and hold yourself.

Build the registration as described in Part 1 of the Office 365 Audit page, granting AuditLog.Read.All and Directory.Read.All as Application permissions on Microsoft Graph. If sign-in records matter to you, add Policy.Read.All as well — without it, appliedConditionalAccessPolicies is not populated on sign-in records.

Before you go that way, consider installing Office365-Audit instead

If you are registering an application and managing a client secret anyway, Office 365 Audit gives you this feed, the unified audit log, an explicit sign-in index and the directory resources from the same registration and the same secret. Unticking this box is the right answer when you specifically want only the directory audit.

Part 2 — Microsoft

This half is performed by the administrator whose address you entered. Everything below is written for them.

What the administrator receives

Fluency sends a message to that address containing a link to Microsoft's admin consent page for the application. Opening it takes them to login.microsoftonline.com, where they sign in and are shown the permission request.

If the administrator reports nothing arriving

Check spam quarantine first. Reinstalling does not change how the request is delivered.

Review the request and accept

Microsoft consent prompt headed Permissions requested, Review for your organization, for the application FluencyAzureADAudit published by Fluency Corp. with a verified publisher badge, listing three permissions

Three permissions are requested — the narrowest set of the three consent templates:

Consent screen wordingPermissionWhat it buys
Sign in and read user profileUser.Read (delegated)Identifies the signing-in administrator during the consent itself. Not used for collection.
Read all audit log dataAuditLog.Read.AllThe directory audit and sign-in endpoints. This is the one the integration exists for.
Read directory dataDirectory.Read.AllUsers, groups, devices and applications — what resolves an object GUID in an audit record to a name.

Three checks before accepting:

  1. The application is FluencyAzureADAudit and the publisher is Fluency Corp. If either is different, stop.
  2. The list is exactly these three. A consent screen asking for more than this is not this integration.
  3. The screen says Review for your organization — that is the tenant-wide grant.

Click Accept. If the administrator clicks Cancel, Microsoft returns AADSTS65004: The resource owner or authorization server denied the request., no grant is created, and nothing on the Fluency side reports it.

Why a read-only audit integration also asks to read the directory

Read all audit log data alone would return records in which every actor and target is a GUID. Read directory data is what turns those into names, and Microsoft also notes that it is needed for something less obvious: "the Directory.Read.All permission is required to retrieve tenant licensing information if it isn't already cached" — which is how the sign-in endpoint decides whether your tenant is entitled to it at all. An application granted only AuditLog.Read.All can see the premium-licence error appear intermittently for that reason.

Neither permission allows any write. Both are read-only, and this application never writes back to the tenant.

What the grant is, and what it is not

Once accepted, the grant lives on the tenant rather than on the administrator who approved it:

  • It does not expire, and there is no secret to rotate.
  • It survives the approver leaving — deactivating the administrator who clicked Accept does not affect collection. This is the main practical advantage of the consent route over a client secret.
  • It is revocable by anyone with the role, from Enterprise applications, without telling Fluency.
  • It does not grant a person anything. No Fluency user gains access to your tenant.

Confirm it is running

Because Running only reports the pipeline, confirm on the Microsoft side first.

In the Microsoft Entra admin center, go to Entra ID → Enterprise apps → All applications and search for FluencyAzureADAudit. If consent was granted, the application is there. If it is not, the request was never accepted.

Enterprise application entry for FluencyAzureADAudit showing the Properties page, its Homepage URL of fluencysecurity.com, and a Delete button in the command bar

To see exactly what was granted, open Security → Permissions and read the Admin consent tab. Its Type column separates Delegated from Application — worth checking here, because Read directory data is worded identically for both and only the application variant is any use to a background collector.

Then, on the Fluency side, check that events are landing in the AzureAudit index — see Confirm data is arriving.

Generate an event you can search for

The directory audit only records changes, so a stable tenant can be genuinely quiet for hours and an empty index proves nothing. To get a definite answer, make a harmless change in Entra — create a group, rename it, delete it — and search the index for it a few minutes later. That distinguishes "nothing has happened" from "nothing is arriving", which the index alone cannot.

Maintenance

There is no credential to rotate

No secret expires, so nothing here needs a calendar entry. What can break the integration is someone revoking the consent, so the maintenance task is review rather than rotation.

Reviewing and revoking the grant

From Entra ID → Enterprise apps → All applications → FluencyAzureADAudit → Permissions → Admin consent, use the ... control on a permission row and select Revoke permission.

The Admin consent tab of an enterprise application's Permissions page, with the Revoke Permission control open on a permission row

Two things about revocation are worth knowing in advance:

  • Nothing tells Fluency. Collection stops and the application keeps reporting Running. On a Free tenant that silence costs a week of data before anyone is likely to notice.
  • Revoking does not stop the application being re-consented. Microsoft notes that "Revoking the current granted permission doesn't stop users from re-consenting to the application's requested permissions." To block it permanently, delete the enterprise application or restrict consent at the tenant level.

Removing the integration

Uninstall the application in Fluency first, with the red Uninstall button at the foot of its details panel. Then, in Microsoft, delete the enterprise application (Properties → Delete) or revoke its permissions as above.

Troubleshooting

SymptomLikely causeFix
The application shows Aborted immediately after installThe index name is already taken — usually AzureAudit from Office365-AuditThe details panel names the index in red. Uninstall the conflicting application, or reinstall this one with a different index name.
The administrator sees Need admin approval rather than a consent screenAADSTS90094 — the account cannot consent to Microsoft Graph application permissionsCloud Application Administrator is not enough for this template. Have a Global Administrator or Privileged Role Administrator open the same link.
Consent fails with AADSTS65004The administrator selected CancelSend the request again. No grant was created.
The administrator never received anythingWrong address, or the message was quarantinedCheck the address on the install form, then spam quarantine.
Running, but the index is empty and has always been emptyConsent was never grantedSearch Enterprise applications for FluencyAzureADAudit. If it is absent, the request was not accepted — resend it.
Running, consent is granted, index still emptyThe tenant may simply be quietThe directory audit only records changes. Make a harmless change in Entra and search for it — see the tip above.
Directory audit records arrive, sign-in records never doThe tenant has no Entra ID P1 or P2 licence — or this template does not poll that endpointExpected on Free. Neither tenant is B2C or tenant doesn't have premium license confirms the licence cause. For a documented sign-in index, use Office 365 Audit.
Sign-in records arrive but appliedConditionalAccessPolicies is emptyPolicy.Read.All was not grantedOnly relevant on the client-secret route; add that permission to your registration. The consent route does not offer it on this application.
The premium-licence error appears intermittently rather than alwaysDirectory.Read.All missing or uncachedMicrosoft notes that permission is what retrieves tenant licensing information. Confirm both permissions are on the Admin consent tab.
Collection worked, then stopped, with no change on our sideThe grant was revoked, or the application was deletedCheck Enterprise applications → Permissions → Admin consent. Re-consent if it is gone.
A gap in the data that will not backfillThe events aged out of EntraUnrecoverable. Seven days on Free, 30 on P1/P2, and Microsoft does not restore expired data.

Under the hood

Engineering reference — the consent flow and the Graph endpoints

The application Fluency operates is registered as multi-tenant in Fluency's own directory. When the administrator approves, they are sent to Microsoft's admin consent endpoint:

https://login.microsoftonline.com/{tenant}/v2.0/adminconsent
?client_id={fluency-client-id}
&scope=https://graph.microsoft.com/.default
&redirect_uri={fluency-callback}
&state={opaque}

Approval produces a redirect carrying admin_consent=True and the tenant GUID, which is why the form never asks for a tenant ID. Older versions of this integration did ask for one, on a Cloud Integrations page that no longer exists.

Collection then uses the client credentials grant against https://graph.microsoft.com/.default. Two artefacts result: application permissions produce an appRoleAssignment on the service principal, and delegated permissions consented tenant-wide produce an oauth2PermissionGrant with consentType: AllPrincipals. Neither references the approving user's account, which is why the grant outlives them.

The Graph endpoints

Both streams are ordinary Graph collections, polled with a timestamp filter and paginated through @odata.nextLink:

GET https://graph.microsoft.com/v1.0/auditLogs/directoryAudits
GET https://graph.microsoft.com/v1.0/auditLogs/signIns

directoryAudits filters on activityDateTime; signIns filters on createdDateTime. Both are backed by AuditLog.Read.All. Sign-ins additionally require the tenant to hold Entra ID P1 or P2, returning Authentication_RequestFromNonPremiumTenantOrB2CTenant otherwise.

appliedConditionalAccessPolicies is populated on sign-in records only when the caller also holds Policy.Read.All, which this application does not request — so on the consent route, expect that field to be absent even on a premium tenant.

What the install creates

The Actions list on the application's details panel records one line per object created. addDatalakeIndex entries create the index in the managed lake as a side effect of the install, which is why a name that already exists aborts the whole application rather than just one stream.

References

Microsoft

Fluency