Mastering Microsoft Entra Authentication Contexts - Part 4: Monitoring and Reporting with KQL & M365IdentityPosture
- Sebastian F. Markdanner
- 6 hours ago
- 8 min read
We’ve covered what Authentication Contexts are, why they matter, and how they help us strengthen access and data security in Microsoft 365.
Now it’s time to answer the next question - how do we monitor and report on their usage?

Unfortunately, there’s no built-in way to gain that visibility today. Neither Entra ID nor Microsoft 365 provides a simple method to inventory or audit Authentication Contexts across our estate including Conditional Access, PIM and Sensitivity labels.
To close that gap, I built a small PowerShell module called M365IdentityPosture.
A project aimed at becoming a unified reporting toolkit for Microsoft Cloud identity and security. Its first feature focuses specifically on Authentication Context reporting, giving you a clear view of which contexts exist, where they’re used, and what they're configured for.
In this post, we’ll explore how to report on and monitor authentication use across our environments, including using the module to generate an Authentication Context Inventory Report, and how to gain (limited) insights using KQL.
Let's jump in!
Table of Contents
Why Monitor Microsoft Entra Authentication Contexts?
As with anything in our environment, there are many reasons to monitor authentication contexts.
These include tracking configuration drift, maintaining documentation, meeting compliance or regulatory requirements, simplifying administrative tasks, and monitoring license utilization.
With Microsoft Cloud’s growing support for authentication contexts, it’s becoming increasingly important to track where they’re deployed and to keep documentation up to date, helping prevent unexpected or breaking changes.
Additionally, by using KQL, we can query sign-in logs to see how often users are prompted to meet the authentication requirements defined by these contexts.
Microsoft Entra Authentication Context Report & Monitor Use-Case
Let’s take a look at a few real-world examples.
Example 1
Contoso hires a new administrator, John Smith.
John is tasked with documenting the deployment and usage of the company’s 32 authentication contexts to meet regulatory compliance requirements that mandate full documentation of all IAM configurations.
Over the years, these authentication contexts were created by multiple admins - some current, some long gone - with no consistent naming conventions, descriptions, or documentation.
To complete the task, John faces digging through various logs, policies, and admin portals, a process that could take hours or even days just to understand how each context is used and by whom.
Example 2
Over time, Contoso’s Conditional Access landscape has evolved.
New authentication contexts have been created and added to policies to support various business needs - some temporary, some experimental - but not all were properly documented or reviewed afterward.
The security team begins to notice inconsistencies between what’s believed to be configured and what’s actually in use. Some authentication contexts appear linked to no active policy, while others are enforced in unexpected scenarios.
Without centralized reporting, identifying which contexts are still relevant, duplicated, or orphaned becomes a slow and tedious manual process.
Documenting Deployed Microsoft Entra Authentication Contexts
As mentioned earlier, documentation and reporting on where each authentication context is deployed can be a pain point for many organizations.
To help ease that pain, I’m introducing the first capability of M365IdentityPosture - the Authentication Context Inventory Report.
This interactive HTML report provides a clear overview of all existing authentication contexts within a tenant, including where they’re used.
Before we dive into the actual report, there’s one caveat to keep in mind:
It’s currently not possible to programmatically collect Microsoft Defender for Cloud Apps (MDCA) Session Policies that use the Require step-up authentication (Auth context) setting. Because of that limitation, these policies aren’t included in the current version of the report.
With that said, let’s take a look at what the report.
Introducing M365IdentityPosture
The (future) one-stop shop for PowerShell M365 Security reports!
What Is M365IdentityPosture?
At its core, M365IdentityPosture is a PowerShell module designed to become a unified reporting toolkit for Microsoft Cloud identity and security.
It’s a living, community-driven project still in its early stages, but with big ambitions.
The current version fills a crucial gap in visibility around Authentication Contexts by providing a comprehensive report that pulls data from all programmatically accessible features that support them.
The inventory report includes:
Authentication Contexts
Conditional Access Policies
PIM Policies for Entra, Groups, and Azure resources
Protected Actions
Sensitivity Labels
Security Groups & Teams
SharePoint Sites
In the next sections, we’ll cover how to install the module and use the Authentication Context Inventory Report.
You can find the full documentation and source code on GitHub: M365IdentityPosture
Installing M365IdentityPosture
As with any tool, let’s start with the prerequisites before diving into installation.
Prerequisites
PowerShell version: The module requires PowerShell 7 or later.
Operating Systems: Windows 10/11, Windows Server 2019+, macOS or Linux
Module Dependencies: The module dynamically loads and unloads these modules during execution, but it does not handle installation automatically. Make sure the following are installed:
Microsoft.Graph.Authentication
Microsoft.Graph.Groups
ExchangeOnlineManagement
Microsoft.Online.SharePoint.PowerShell
Az.Accounts
Az.Resources
Installation Options
You can install M365IdentityPosture either from the PowerShell Gallery or manually from GitHub.
PSGallery installation option
# Install the module via PSGallery
Install-Module -Name M365IdentityPosture
# Import the moddule
Import-Module -Name M365IdentityPostureManual installation option
# Download or clone the repository
git clone https://github.com/Noble-Effeciency13/M365IdentityPosture.git
# Copy to user module path
$modulePath = "$HOME\Documents\PowerShell\Modules\M365IdentityPosture"
Copy-Item -Path ".\M365IdentityPosture\*" -Destination $modulePath -Recurse -Force
# Import the module
Import-Module -Name M365IdentityPostureRunning the Authentication Context Inventory Report
Since the report gathers data from across your Microsoft 365 estate, a few permissions are required.
It uses the Microsoft Graph Command Line Tools (formerly Microsoft Graph PowerShell) enterprise application with delegated permissions, all of which must be granted to the user running the report.
Required Microsoft Graph Delegated API permissions:
Directory.Read.All
Group.Read.All
Policy.Read.All
Policy.Read.ConditionalAccess
PrivilegedAccess.Read.AzureADGroup
InformationProtectionPolicy.Read.All
Required Service-Specific Permissions:
Exchange Online: View-Only Organization Management OR Global Reader
SharePoint Online: SharePoint Administrator OR Global Reader
Azure: Reader role on Subscriptions or Management Groups (for Azure PIM Policy enumeration)
With the module installed and permissions in place, running the report is simple, just invoke it and let the magic happen.
On the first run, you’ll be prompted to grant Graph consent.
Importing M365IdentityPosture & Get-Help Functionality
When you import the module, it displays the current version and available public commands.
Each command includes comment-based help, which you can access with the standard Get-Help command to view parameters and examples.
To view help for the Authentication Context Inventory Report:
Get-Help Invoke-AuthContextInventoryReport -Detailed
Invoking the Authentication Context Inventory Report
When you run the report without the -Quiet parameter, you’ll see progress updates in the console for each phase, along with a summary at the end.
For large Azure environments, you can skip Azure PIM policy enumeration (which can take time) to speed things up.


Navigating the Authentication Context Inventory Report
Once complete, the report generates an interactive HTML report showing all deployed authentication contexts across your environment, excluding MDCA Session Policies as noted earlier.

This report provides an easy, effective way to document and track authentication contexts across your organization, ensuring you stay on top of documentation and change tracking requirements.
And let’s be honest - that’s often the worst part of any technical implementation.
Monitoring Usage of Authentication Contexts Using KQL
As mentioned earlier, there’s currently no built-in way to monitor or report on the utilization of Authentication Contexts, at least not directly.
However, through Microsoft Entra sign-in logs, we can identify when a user’s sign-in is affected by a Conditional Access policy scoped to an authentication context.
That means we can query these events using KQL, whether the data resides in a Log Analytics workspace, Microsoft Sentinel, a Graph-based third-party integration, or Azure Monitor.
The challenge with this approach is that we can’t always determine exactly what triggered the authentication prompt.
But when you combine the M365IdentityPosture report from earlier, with the following KQL query, you can start drawing meaningful connections - who was affected, what was required, and when it happened.
KQL: Identify and Map Authentication Context Usage
The query below searches the last 30 days of sign-in logs for sign-ins requiring an ACR claim (Authentication Context).
It then attempts to identify which Conditional Access policy required that context.
If it can’t find a direct match, it lists all successful Conditional Access policies from the same sign-in to help narrow it down.
SigninLogs
| where TimeGenerated between (ago(30d) .. now())
| where isnotempty(AuthenticationContextClassReferences)
| extend ACR = todynamic(AuthenticationContextClassReferences)
| mv-expand ac = ACR
| extend d = todynamic(ac)
| extend AuthContextId = coalesce(tostring(d.id), tostring(ac)),
AuthContextDetail = tolower(tostring(d.detail))
| where AuthContextDetail == "required" and isnotempty(AuthContextId)
| extend AppliedCAPs = todynamic(coalesce(column_ifexists("AppliedConditionalAccessPolicies", dynamic(null)),
column_ifexists("AppliedConditionalAccessPolicies_dynamic", dynamic(null)), dynamic([]))),
ConfigCAPs = todynamic(coalesce(column_ifexists("ConditionalAccessPolicies", dynamic(null)),
column_ifexists("ConditionalAccessPolicies_dynamic", dynamic(null)), dynamic([])))
| extend PoliciesAll = array_concat(AppliedCAPs, ConfigCAPs)
| mv-apply pol = PoliciesAll on (
extend polId = tostring(coalesce(pol.policyId, pol.id)),
polName = tostring(coalesce(pol.displayName, pol.policyName)),
polRes = tostring(pol.result),
polAcrs = todynamic(pol["conditions"]["applications"]["authenticationContextClassReferences"]),
polJson = tostring(pol)
| extend matched = iif(isnotempty(polAcrs) and array_index_of(polAcrs, AuthContextId) >= 0, 1,
iif(polJson has_cs "\"authenticationContextClassReferences\"" and polJson has_cs strcat("\"", AuthContextId, "\""), 1, 0))
| project polId, polName, polRes, matched
)
| summarize
RequiringPolicyIds = make_set_if(polId, matched == 1, 50),
RequiringPolicyNames = make_set_if(polName, matched == 1, 50),
CandidatePolicyIds = make_set_if(polId, polRes =~ "success", 50),
CandidatePolicyNames = make_set_if(polName, polRes =~ "success", 50)
by TimeGenerated, Id, UserPrincipalName, UserId,
AppDisplayName, ResourceDisplayName, ClientAppUsed,
AuthContextId, IPAddress, SessionId
| project
SignInTime = TimeGenerated,
UserPrincipalName, UserId,
AppDisplayName, ResourceDisplayName, ClientAppUsed,
AuthContextId,
RequiringPolicyIds, RequiringPolicyNames,
CandidatePolicyIds, CandidatePolicyNames,IPAddress, SessionId
| order by SignInTime descExample Output – Authentication Context Usage Query
The KQL query returns detailed sign-in activity where authentication contexts were applied.
In this example, we can see a sign-in to Microsoft Graph Command Line Tools that required the authentication context c1. While no directly linked Requiring Policies were identified, several Candidate Policies appear helping to narrow down which Conditional Access policies may have triggered the requirement.

This query helps visualize authentication context activity across your environment and connect the dots between configuration and real-world usage.
While it doesn’t reveal the exact trigger behind each authentication prompt, it provides valuable insights into which policies are most active, who’s being challenged, and how authentication contexts are applied in practice.
Conclusion: From Configuration to Clarity
Throughout this mini-series, we’ve taken a deep dive into Microsoft Entra Authentication Contexts, from understanding what they are and how they strengthen access security and data protection, to deploying, documenting, and now monitoring them across your environment.
As we’ve seen, authentication contexts can easily multiply and drift over time, especially in large or long-lived tenants. Without proper visibility, that complexity can quickly turn into a compliance or operational headache.
By combining structured documentation through the M365IdentityPosture module with data-driven monitoring using KQL, we gain both perspectives:
The static view of how contexts are configured
The dynamic view of how they’re actually used
Together, they create the foundation for effective governance, cleaner IAM hygiene, and stronger audit readiness.
With better visibility, ongoing documentation, and consistent monitoring in place, managing authentication contexts stops being a guessing game and becomes a structured, repeatable process — one that scales as your organization grows.
You can find the full Mastering Microsoft Entra Authentication Contexts series below, and the M365IdentityPosture source code on my GitHub.
And now, to close out the series - the mandatory bad joke
Yesterday my son came home and asked me,
“Dad, my teacher told me never to name a boat after anything cloud related — why not?”
I told him,
“Oh, that’s because there’s a much higher chance of it syncing.”😎
🔗 Authentication Context Series Index
Part 3: Advanced Data Security
Part 4: Monitoring and Reporting with KQL & M365IdentityPosture (You're here!)
