Azure Identity

Why Was I Blocked? Diagnosing Conditional Access from Entra Sign-In Logs

A VIP forwards you a screenshot: a grey Entra page saying their organisation’s Conditional Access policy has blocked the sign-in, with a request ID and a timestamp and nothing else. The user swears nothing changed. Maybe nothing did on their side; something always changed somewhere. This is the most common identity ticket in any Entra-governed tenant, and it is maddening for the same reason an App Service 502 is maddening: the screen the user sees is the enforcement point’s verdict, not the reason. The block page tells the user almost nothing — surfacing policy logic to an unauthenticated browser would leak security detail — so the real answer lives somewhere else: the Entra sign-in logs.

This is the diagnostic playbook for that answer. Every sign-in event carries a top-level conditionalAccessStatus (did CA succeed, fail, or not apply?), an appliedConditionalAccessPolicies array that names every policy evaluated and its result for this sign-in, and a failure reason with a numeric error code (53003 blocked by policy, 50074 MFA required, 53000 device not compliant, 50158 an external grant control unmet) that pins the block to a specific control. Learn to read those three things and you stop guessing — localising any block to the exact policy, the exact control, and the exact condition that matched, using the Sign-in logs blade, the What If tool, Microsoft Graph, and KQL over SignInLogs.

By the end you will read a blocked sign-in the way a senior identity engineer does: open the event, glance at conditionalAccessStatus, expand the Conditional Access tab to find the one policy whose result is failure, read which grant control it required and which condition put the user in scope, and know within ninety seconds whether you face a genuine policy gap, a user who isn’t enrolled for MFA, a non-compliant device, an unexpected location, or a legacy-auth client that can’t satisfy modern controls at all. Knowing which is the difference between a five-minute fix and a day of poking at policies in production.

What problem this solves

Conditional Access hides enormous machinery so that “require MFA for admins” becomes a checkbox. That abstraction is a gift until a sign-in is blocked, then it becomes an opaque wall: the block page is intentionally vague, the user’s description (“it just stopped working”) is unreliable, and a tenant of any size runs a dozen overlapping policies whose combined effect on one sign-in from one device in one location is hard to predict in your head. The information you need is captured — Entra logs every policy it evaluated for every sign-in — but if you don’t know which field answers which question, you burn an hour clicking, or worse, start disabling policies in production to see what happens. That loosens a policy (a hole auditors find later), excludes a user (a standing exception nobody revisits), or has them “try again” until a transient MFA prompt succeeds — teaching everyone the wrong lesson.

Who hits this: every organisation that has rolled out Conditional Access — now most, since security defaults and baseline policies push MFA and legacy-auth blocking by default. It bites hardest right after a new policy ships (a wave of unexpected blocks), during migrations (a service account on legacy auth suddenly blocked), for travelling executives (location and device conditions), and for anyone enabling device-compliance or phishing-resistant-MFA controls without first watching the impact in report-only mode. The fix is almost never “turn the policy off” — it’s “read the log, find the control that wasn’t satisfied, and decide whether the user should satisfy it or be legitimately scoped out.”

To frame the whole field before the deep dive, here is every block class this article covers, the question it forces, and the one field to read first:

Block class What the enforcement point is saying First question to ask First field to read Most common single cause
Hard block (access denied) “A policy’s grant control was Block access Which policy returned failure with a Block control? appliedConditionalAccessPolicies[].result = failure A Block legacy authentication or Block by location/platform policy matched
Grant not satisfiable “A required control couldn’t be met by this sign-in” Was it MFA, compliant device, or a managed app? Failure reason code (50074/53000/53003) User not MFA-registered, or device not compliant
MFA interrupt (not a block) “Step-up required” — the user just didn’t complete it Did the user actually finish the prompt? status + conditionalAccessStatus Legitimate MFA challenge abandoned/failed
Unexpected scope-in “A policy applied that you didn’t expect” Which condition matched (app/location/risk/platform)? conditionsNotSatisfied / the conditions tab Broad “All cloud apps” + a missing exclusion
Unexpected scope-out “A policy you wanted didn’t apply” Why was the user not in scope? result = notApplied + the conditions An exclusion group, trusted location, or filter

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should understand the shape of Conditional Access: a policy is an if-then statement — if these assignments match (users/groups, target resources, and conditions like location, device platform, client app, sign-in risk) then apply these access controls (grant controls — require MFA, require compliant device, require app protection, or block access; and session controls — sign-in frequency, app-enforced restrictions). Know that CA requires Entra ID P1 (P2 adds risk-based conditions), that policies evaluate after first-factor auth succeeds, and that all matching policies combine — grant controls are ANDed across policies. You should be comfortable in the Entra admin center and able to run az/Graph queries and read JSON.

This sits in the Identity & Access track, squarely in its troubleshooting corner. It assumes you have policies deployed — ideally the way the companion piece Deploying Conditional Access Safely: Report-Only Rollout to Enforcement lays out — and it pairs with the deeper identity concepts in OIDC and OAuth2 on Entra ID: Choosing the Right Flow, because what kind of sign-in (interactive auth-code vs client-credentials vs device-code) decides which controls can even be satisfied. When the block involves MFA method registration, Authenticator Passkeys and Number Matching: Stopping MFA Fatigue Attacks is the adjacent topic; when it involves desktops, Conditional Access for AVD and Windows 365 covers that surface. If the logs themselves aren’t arriving in Log Analytics, that’s a different problem — see No Logs Showing Up? Troubleshooting Empty Log Analytics Tables.

A quick map of who confirms what during a sign-in incident, so you escalate to the right owner fast:

Layer What lives here Who usually owns it Block classes it can cause
First-factor auth Password / passkey / federation Identity team 500xx auth errors before CA even runs (not CA)
CA policy evaluation Assignments, conditions, grant/session controls Identity / security Hard block, grant-not-satisfied, scope surprises
MFA registration & methods Authenticator, FIDO2, phone, OATH Identity + helpdesk 50074/53004 — user not registered / can’t step up
Device state Intune compliance, Entra join/registration Endpoint team 53000/53001/53002 — device controls
App / client type Browser, mobile/desktop app, legacy client App + identity 53003 block legacy auth; app-protection grant
Network / location Named locations, trusted IPs, GSA Network + identity Location conditions scoping the policy in or out

Core concepts

Five mental models make every later diagnosis obvious.

The block page names the enforcement point’s verdict, not the reason. The browser shows a generic interrupt with a request ID (the correlation ID) and a timestamp — by design. The reason — which policy, which control, which condition — is written to the sign-in log for that exact event. So the first move in every Conditional Access ticket is not “look at the policy”; it is “find the sign-in event” by user, time, and ideally request ID, and read what Entra recorded.

conditionalAccessStatus is the first fork. Every sign-in carries one of: success (CA applied, every required control satisfied), failure (CA applied, at least one control not satisfied — your block or unsatisfied grant), notApplied (no policy’s assignments matched, so CA did nothing), or notEnabled (CA not licensed/configured). “Did CA even fail?” versus “did CA not apply at all?” is the same first fork that 502-vs-503 is for App Service — it tells you instantly whether you’re chasing a policy that fired or one that should have fired but didn’t.

The appliedConditionalAccessPolicies array is the whole story. This per-sign-in array lists every policy Entra evaluated — not just the one that blocked — each with a result: success, failure, notApplied, notEnabled, or the report-only variants (reportOnlySuccess/Failure/NotApplied/Interrupted). For a block you scan for the row whose result is failure, then read its enforcedGrantControls (Mfa, Block, CompliantDevice, RequireAppProtection) and enforcedSessionControls to see what it demanded. One sign-in can have several policies in failure — the user must satisfy all of them.

Grant controls are ANDed across policies; “Block” wins outright. Within one policy you pick require all or require one of the selected controls. Across multiple applicable policies they combine with AND — the user must meet every required control from every policy in scope. A Block access control is absolute: if any applicable policy says Block, the sign-in is denied regardless of what else the user could satisfy. This is why “I have MFA, why am I blocked?” is common — MFA satisfied policy A, but policy B required a compliant device the user lacked, or policy C blocked the legacy client outright.

Failure reason ≠ error: the code is a diagnosis, not a bug. The error code names the control that wasn’t met, not a system fault. 53003 means a grant control denied access; 50074 means MFA was required and not completed; 53000 means a compliant device was required and this one isn’t. The code tells you the fix category before you open the policy: enrol the user, fix device compliance, scope the policy, or unblock the client.

The vocabulary in one table

Before the deep sections, pin down every moving part. The glossary at the end repeats these for lookup; this table is the mental model side by side:

Concept One-line definition Where it lives Why it matters to a block
Policy (CA) An if-then rule: assignments → access controls Entra → Conditional Access The thing that blocks or challenges
conditionalAccessStatus success / failure / notApplied for the sign-in Sign-in log (top level) The first fork: did CA fail or not apply?
appliedConditionalAccessPolicies Array of every policy evaluated + its result Sign-in log → Conditional Access tab Names the policy and control that blocked
result (per policy) success / failure / notApplied / reportOnly* In the array failure = this policy wasn’t satisfied
Grant control Require MFA / compliant device / block, etc. Policy → Grant What the user had to satisfy
Session control Sign-in frequency, app-enforced restrictions Policy → Session Re-auth cadence; app-side limits
Failure reason / code Why it failed (53003, 50074, …) Sign-in log (Basic info) Maps the block to a specific control
Named location An IP range / country marked trusted or not Entra → Named locations Conditions that scope a policy in/out
Report-only Policy evaluated but not enforced Policy state Predicts blocks without blocking
What If Simulator for “which policies apply to X?” Conditional Access → What If Confirms scope without a real sign-in
Sign-in risk Real-time/aggregate risk level (P2) Identity Protection A risk condition can scope a policy in
Filter for devices Rule over device attributes Policy condition Scopes by device properties, not compliance

How an Entra sign-in record is structured

You cannot diagnose what you cannot read, and the sign-in record has a lot in it. Open Entra admin center → Identity → Monitoring & health → Sign-in logs, click a single event, and you get a flyout with several tabs. The fields that matter for a Conditional Access block, and where each one lives:

Tab / field What it tells you Why it matters to a block
Basic info → Status Success / Failure / Interrupted Top-line outcome of the whole sign-in
Basic info → Sign-in error code Numeric code + failure reason The diagnosis (53003, 50074, …)
Basic info → Conditional Access Success / Failure / Not applied conditionalAccessStatus at a glance
Basic info → Correlation / Request ID The ID on the user’s block page Lets you match the user’s screenshot to the event
Conditional Access tab The appliedConditionalAccessPolicies array Per-policy result + the controls it enforced
Device info tab Device ID, OS, compliant, managed, join type Confirms a device-control failure
Authentication details tab Which methods were tried/satisfied (MFA) Confirms whether MFA actually completed
Location IP, city, country, named-location match Confirms a location condition scoped the policy
Additional details Client app, app/resource, user agent Confirms legacy auth, the target app, the platform

The first three you read in two seconds: Status = Failure, Conditional Access = Failure, error code = 53003 is the canonical “blocked by policy” signature. But Status can be Interrupted (an MFA challenge that wasn’t completed) rather than Failure, and that distinction matters enormously — an interrupt is the user not finishing, a failure is a control that couldn’t be met. The combinations you will actually see, decoded:

Status Conditional Access Error code What it means Where to go next
Success Success 0 CA applied, all controls met Nothing wrong — it worked
Failure Failure 53003 A grant control denied access (Block, or unmet required control) Conditional Access tab → the failure policy
Interrupted Success 50074 / 50076 / 50079 MFA was required; user didn’t complete it (this attempt) Authentication details; was the prompt finished?
Failure Failure 53000 / 53001 / 53002 A device control wasn’t met (not compliant / not joined / not managed) Device info tab + Intune compliance
Failure Failure 53004 User must register for MFA before this works Authentication methods registration
Failure Failure 50158 An external/secondary grant control wasn’t satisfied (e.g. T&C, custom control) The policy’s grant controls
Success Not applied 0 No policy matched this sign-in Expected — or a scope-out surprise
Failure Not applied various The sign-in failed for a non-CA reason It’s not Conditional Access — look at auth

That last row is the most common false alarm: a wrong password (50126) or a disabled account (50057) is not a Conditional Access block, even though the user says they were blocked. If conditionalAccessStatus is notApplied and the error is a 500xx auth code, stop looking at policies — the failure happened before CA evaluated.

The Conditional Access failure-reason reference

This is the lookup table you scan first. Every code below is a real Entra AADSTS/sign-in error you will encounter; the column that earns its keep is how to confirm (so you don’t fix the wrong thing) and the control it maps to.

Code Failure reason (short) Control / condition it maps to How to confirm First fix
53003 Access blocked by Conditional Access A grant control denied (Block, or an unmet require control) CA tab → policy with result=failure; read enforcedGrantControls Satisfy the control, scope the user out, or remove the Block
50074 Strong auth (MFA) required Require MFA grant control Authentication details — MFA not completed this attempt Complete MFA; ensure user has a usable method registered
50076 MFA required (from a non-trusted location / re-auth) Require MFA (often + location) Location tab + CA tab Complete MFA; check the location condition is intended
50079 MFA registration and challenge required Require MFA, user has no method Authentication methods → registration state Register an MFA method (Authenticator/FIDO2/phone)
53004 User must enrol for MFA Require MFA before first use Registration campaign / methods blade Drive the user through MFA registration
53000 Device is not compliant Require compliant device Device info → isCompliant=false; Intune Remediate compliance in Intune, or fix the policy scope
53001 Device is not Entra-joined / registered Require Hybrid/Entra joined device Device info → join type Join/register the device, or relax the requirement
53002 App not approved / not managed Require approved client app / app protection Additional details → client app Use an approved app; apply the app-protection policy
50158 External security challenge not satisfied A custom/secondary grant control (T&C, custom controls) CA tab → the policy’s grant controls Accept terms / satisfy the custom control
50097 Device authentication required Device condition / certificate Device info; certificate presence Provide device cert / join state the policy expects
530032 Blocked by security info registration interrupt Security info / MFA registration policy Registration policy state Complete required security-info registration
500121 Authentication failed during MFA request MFA method failed/timed out/denied Authentication details — method + result User retries; check method health (number match denied?)

Three reading notes that save the most time:

Distinction The trap How to tell them apart
53003 (CA block) vs a 500xx auth error “Blocked” is overloaded; users say it for any failure 53003 has conditionalAccessStatus = failure; 500xx auth errors have notApplied and happen before CA
MFA interrupt vs MFA failure An abandoned prompt looks like a block Status Interrupted + a later successful sign-in = user just didn’t finish; persistent failure = no usable method
Block-control vs unsatisfied-require-control Both surface as 53003 Read enforcedGrantControls: Block = hard block; Mfa/CompliantDevice = a require the user can satisfy

Anatomy of a hard block (access denied)

A hard block is the cleanest case: an applicable policy’s grant control is Block access, so the sign-in is denied no matter what the user could otherwise satisfy. Five distinct triggers. Scan the matrix, then read the detail for whichever row matches:

# Block trigger Tell-tale signal Confirm with Real fix Band-aid that masks it
1 Block legacy authentication matched clientAppUsed = “Other clients” / IMAP/POP/SMTP Additional details → client app Move the client to modern auth (OAuth) Excluding the app (re-opens legacy auth hole)
2 Block by location Sign-in from an untrusted country/IP Location tab + named-location match Add the location to trusted, or scope the policy Disabling the location policy entirely
3 Block by device platform Sign-in from an unsupported OS (e.g. Linux) Device info → OS / platform condition Use a supported platform, or scope the policy Removing the platform condition wholesale
4 Block specific app / all but a few Target app is in (or not excluded from) the policy CA tab → target resources Exclude the app intentionally, or grant access Broadening “All cloud apps” exclusions blindly
5 Filter-for-devices block rule Device attribute matched a block filter Device info → attributes vs filter rule Fix the device attribute or the filter expression Deleting the filter (loses the protection)

Trigger 1 — Block legacy authentication

The single most common intentional hard block. A Block legacy authentication policy targets the legacy authentication clients condition (Exchange ActiveSync and “Other clients” — IMAP, POP3, SMTP AUTH, MAPI over HTTP, older Office) and grants Block access. Legacy protocols can’t do interactive MFA, so they’re a favourite for password spray — blocking them is correct. But an old mail client, a printer’s scan-to-email, or a basic-auth script then gets a flat denial with no idea why.

Confirm. Event → Additional detailsClient app shows a legacy value (IMAP4, POP3, SMTP, Exchange ActiveSync, or the catch-all “Other clients”); the Conditional Access tab shows the policy with result = failure and enforcedGrantControls = [Block]. In KQL:

// Legacy-auth sign-ins blocked by CA in the last 24h
SigninLogs
| where TimeGenerated > ago(24h)
| where ConditionalAccessStatus == "failure"
| where ClientAppUsed in ("Other clients","IMAP4","POP3","SMTP","Exchange ActiveSync","MAPI Over HTTP","Authenticated SMTP")
| project TimeGenerated, UserPrincipalName, AppDisplayName, ClientAppUsed, ResultType, Status
| order by TimeGenerated desc

Fix. Move the client to modern authentication (OAuth 2.0) — reconfigure the mail client or switch the script to a token flow. Do not simply exclude the app or user from the block: that re-opens the exact hole the policy closes. If a service genuinely cannot use modern auth, scope the exception as narrowly as possible — a single service identity, ideally a workload identity using the right OAuth flow — and document it.

Trigger 2 — Block by location

A location condition — “all locations, exclude trusted” with a Block grant, or “include these countries” — denies sign-ins from places you don’t operate. A travelling executive in a blocked country, or a user behind a VPN egressing from an unexpected region, hits a flat block.

Confirm. The Location tab shows the source IP, resolved city/country, and whether it matched a named location; compare against the policy’s location condition (Entra → Named locations).

// Blocks where a location condition was in play, with the source country
SigninLogs
| where TimeGenerated > ago(7d) and ConditionalAccessStatus == "failure"
| extend country = tostring(LocationDetails.countryOrRegion), city = tostring(LocationDetails.city)
| project TimeGenerated, UserPrincipalName, IPAddress, country, city, AppDisplayName, ResultType
| order by TimeGenerated desc

Fix. If the location is legitimate, add it as a trusted named location (or add the country to the allowed set) — don’t disable the policy. If the GeoIP is simply wrong (it happens), that’s a strong argument to base the condition on trusted IP ranges you control rather than country lookups — see the location grid below.

Trigger 3 — Block by device platform

A device platform condition (Windows / iOS / Android / macOS / Linux) with a Block grant denies unsupported platforms — e.g. a policy allowing only managed Windows and iOS quietly blocks a developer on Linux or a personal Chromebook. The Device info tab shows the OS; the platform is inferred from the user agent for browser sign-ins, so an unusual or spoofed agent can mis-match. Fix: add the platform to the allowed set if needed, or scope the policy — don’t strip the condition globally for one user.

Trigger 4 — Block by app / target resource

The policy’s target resources include the app the user is reaching — or it’s “All cloud apps” with the app not excluded — and a Block grant denies it. This is also how a “block all but the approved apps” policy works, and how it catches a new app nobody added to the allow list. Additional details shows the Application and Resource; match it against the policy. Find the surprise target in KQL:

// Which app is being blocked, grouped — find the surprise target
SigninLogs
| where TimeGenerated > ago(24h) and ConditionalAccessStatus == "failure" and ResultType == 53003
| summarize blocks = count() by AppDisplayName, ResourceDisplayName
| order by blocks desc

Fix: add the app to the exclusions deliberately if it should be allowed; otherwise the policy is working and the app simply isn’t permitted.

Trigger 5 — Filter for devices

A filter for devices rule scopes by device attributes (model, ownership, extensionAttribute, trustType) rather than compliance; a block filter (or an include the device doesn’t match) can deny an otherwise-fine device. The Device info tab shows the attributes — a mismatched extensionAttribute from a stale provisioning script is a frequent culprit. Fix: correct the attribute (re-stamp via Graph/Intune) or the filter expression, and test it in What If before re-enforcing.

The location-related controls deserve their own grid — what each is, and the gotcha:

Location mechanism What it is Where set Gotcha
IP-range named location CIDR ranges you mark trusted Named locations Must be the egress (public) IP, not the client’s private IP
Country/region named location Locations by GeoIP or sign-in country Named locations GeoIP can be wrong; VPN egress shifts the country
MFA trusted IPs (legacy) Old per-tenant trusted-IP list Per-user MFA service settings Separate from named locations; easy to forget it exists
Compliant network Microsoft-defined network compliance signal Global Secure Access Requires GSA; not the same as a named location
GPS-based country (Authenticator) High-assurance location via the app Named locations (GPS) Prompts the user; not available for all sign-in types

Anatomy of a grant-not-satisfied block

This is the larger, subtler family: the policy did not say “Block” — it required a control (MFA, a compliant device, an approved app, app protection) that this sign-in didn’t satisfy. The user could get in; they just haven’t met the bar yet. The surface code is usually still 53003 (or an MFA-specific 500xx), so you must read the enforced grant controls to know which.

# Unsatisfied control Tell-tale signal Confirm with Real fix
1 Require MFA — user not registered 50079/53004; no methods registered Authentication methods blade Register a method (Authenticator/FIDO2/phone)
2 Require MFA — challenge not completed Status Interrupted; 50074 Authentication details User completes the prompt; check method health
3 Require compliant device 53000; isCompliant=false Device info + Intune compliance Remediate compliance; or scope the requirement
4 Require Entra/Hybrid-joined device 53001; join type wrong Device info → join type Join/register the device
5 Require approved app / app protection 53002; client app not approved Additional details → client app Use an approved app with an applied APP policy
6 Require phishing-resistant MFA 53003 + Mfa strength unmet Authentication strength in the policy Register a passkey/FIDO2/CBA method

Cause 1 & 2 — Require MFA, but it wasn’t (or couldn’t be) completed

Two flavours hide here. In the first, the user has no usable MFA method registered, so when a policy requires MFA the sign-in fails with 50079 or 53004 (“you must register before you can do this”). In the second, the user is registered but didn’t complete the challenge this attempt — they dismissed the Authenticator push, denied the number match, let it time out, or hit a flaky network — and the sign-in shows Status = Interrupted with 50074. The second is not really a block at all; the next attempt usually succeeds.

Confirm. The Authentication details tab lists each method attempted and its result (“MFA denied; user declined the authentication”, “MFA successfully completed”, or no method at all). For registration state, Entra → Authentication methods → User registration details (or the userRegistrationDetails Graph API) shows whether the user has any method.

// MFA-driven interrupts vs hard failures in the last day
SigninLogs
| where TimeGenerated > ago(1d)
| where ResultType in (50074, 50076, 50079, 53004)
| project TimeGenerated, UserPrincipalName, ResultType, ResultDescription, Status, AppDisplayName
| order by TimeGenerated desc

Fix. For the unregistered user, drive registration — an MFA registration campaign, or a temporary report-only rollout that lets you find the unregistered population before you enforce. For the abandoned-prompt case, the fix is usually user education plus making the prompt easier to satisfy — number matching and passkeys reduce both fatigue and accidental denials. A genuinely repeating 500121 (MFA denied) from one user is worth a security glance: it can be the user reflexively denying a legitimate prompt, or an attacker triggering prompts the user is correctly rejecting.

Cause 3 & 4 — Require compliant or joined device

A policy requires a compliant device (Intune-managed and passing its compliance policy) or an Entra-joined / Hybrid-joined device, and the sign-in comes from one that isn’t — codes 53000 (not compliant) and 53001 (not joined/registered). The device may have been compliant then drifted (expired evaluation, a disk-encryption check that began failing, an OS version below the bar), so it’s blocked today with nothing the user did.

Confirm. The Device info tab shows Compliant: false, the join type, and the device ID; cross-check Intune → Devices → the device → Compliance to see which setting failed.

// Device-control blocks with the device state inline
SigninLogs
| where TimeGenerated > ago(2d) and ResultType in (53000, 53001, 53002)
| extend isCompliant = tostring(DeviceDetail.isCompliant), join = tostring(DeviceDetail.trustType), os = tostring(DeviceDetail.operatingSystem)
| project TimeGenerated, UserPrincipalName, ResultType, isCompliant, join, os, DeviceDetail.displayName
| order by TimeGenerated desc

Fix. Remediate the actual compliance failure in Intune (re-encrypt, update the OS, re-enrol). If the device should be exempt (a kiosk, a specific role), scope the policy rather than mark a non-compliant device compliant. A common operational trap: the device shows compliant in Intune but the sign-in still says 53000 because the compliance state hadn’t synced to Entra at sign-in time — a forced sync or a short wait resolves it, and that’s worth checking before you touch the policy.

Cause 5 & 6 — Require approved app / app protection / stronger MFA

A policy requires an approved client app or an app protection policy (APP / MAM) — common for mobile Exchange/SharePoint — and the user reaches the resource from an unapproved app (native iOS Mail instead of Outlook): code 53002. Or it demands an authentication strength (phishing-resistant MFA) the user’s method can’t meet — they did a form of MFA, but not a passkey/FIDO2/certificate. Additional details → Client app (and the policy’s grant controls / required strength) confirms which. Fix: move the user to an approved app with the APP policy applied, or get a phishing-resistant method registered — don’t downgrade the requirement to clear one ticket when it’s the security goal.

Scope surprises: when the wrong policies (or none) apply

Half of “why was I blocked” tickets aren’t about an unsatisfied control at all — they’re about scope: a policy applied that you didn’t expect (scope-in), or one you wanted didn’t apply (scope-out). Both are read from the conditions and the per-policy result.

Surprise What you see Likely cause Confirm with
Unexpected scope-in A policy with result=failure you didn’t think applied Broad “All cloud apps”, a group the user is unexpectedly in, a matched condition CA tab → that policy’s assignments; What If
Unexpected scope-out A policy you wanted shows result=notApplied An exclusion group, a trusted location, a device filter, or the user not in the include set CA tab → notApplied + conditions
“Required by both” confusion Two policies in failure, user met one Grant controls AND across policies Read every failure row’s enforcedGrantControls
Report-only “would have blocked” reportOnlyFailure in the array A not-yet-enforced policy would block Report-only results; the workbook
No policy at all conditionalAccessStatus = notApplied Nothing matched — or it’s not a CA problem Check it isn’t a 500xx auth error

Unexpected scope-in

The user was blocked by a policy you assumed didn’t target them — almost always because it targets All cloud apps (so it applies by default), the user is in a group that’s in the include set (membership changed, or a nested group pulled them in), or a condition matched unexpectedly (untrusted location, device platform, risk). The dangerous version is a broad policy with a missing exclusion — a break-glass account that should be excluded but isn’t. The Conditional Access tab shows the offending policy’s assignments; the fastest non-destructive confirmation is What If (below), which lists exactly which policies would apply and why without a real sign-in.

Unexpected scope-out

The opposite, and more dangerous because it’s silent: a policy you intended to protect this sign-in shows result = notApplied, so a sign-in you wanted to challenge sailed through. Causes: the user (or their group) is excluded, the sign-in came from an excluded trusted location, a device filter excluded the device, or they’re not in the include set. Standing exclusions are the usual villain — a “temporary” one that became permanent. The notApplied result plus the conditions (and What If) tells you which assignment dropped them. This is the audit you run after a security review to prove a high-value app is actually covered.

The result values in the array, fully decoded — the report-only ones trip people up:

result value Meaning Enforced? What to do
success Policy applied; controls satisfied Yes Nothing — working as intended
failure Policy applied; a control was not satisfied Yes This is your block — read the controls
notApplied Assignments didn’t match this sign-in No Expected, or a scope-out to investigate
notEnabled Policy is Off No Turn it On if it should be active
reportOnlySuccess Report-only; controls would be satisfied No Safe to enforce for this case
reportOnlyFailure Report-only; would have blocked/challenged No This is the blast radius — fix before enforcing
reportOnlyNotApplied Report-only; would not have applied No Out of scope when enforced
reportOnlyInterrupted Report-only; would have interrupted (MFA) No The user would be challenged when enforced

Driving the diagnostic tools

Four tools answer 95% of these questions. Knowing which one answers your question is the whole skill.

The Sign-in logs blade and its four tabs

The logs are split because not every sign-in is a person at a browser. The four tabs:

Tab What it shows When CA blocks show here
Interactive user sign-ins A human authenticating (browser, MFA prompts) Most user-facing CA blocks
Non-interactive user sign-ins Token refreshes, background app calls on a user’s behalf Silent re-eval blocks (sign-in frequency, revoked)
Service principal sign-ins App-only (client-credentials) sign-ins Workload identity CA policies (P-Workload)
Managed identity sign-ins MI token acquisitions Rarely CA-gated; useful for completeness

The trap: an admin searches Interactive sign-ins, finds nothing, and concludes “there’s no block” — when the failing sign-in is a non-interactive token refresh (a session-frequency policy forcing re-auth a background process can’t do) or a service principal call governed by a workload-identity policy. If an app “just stops working” with no prompt, check the non-interactive tab. Filter by user, time, status, application, and crucially Conditional Access = Failure to cut straight to blocks.

What If — simulate before you touch anything

Conditional Access → What If is the simulator. You specify a user, a target resource/app, and optional conditions — IP address (hence country/named-location match), device platform, client app, sign-in risk, user risk — and Entra evaluates all your policies against that hypothetical sign-in, returning which would apply (and the controls they’d enforce) and which would not apply, with the reason. It’s the safest way to answer “would this user be blocked from this app at this location?” without making them try and fail, and it’s how you prove a fix before you ship it.

The key caveat: What If evaluates policy logic, not live state. It will say “Require compliant device would apply” but doesn’t know whether the user’s laptop is compliant right now, run a real MFA check, or predict transient failures — for outcomes you still read a real sign-in or check Intune. Use What If for scope; use report-only and real logs for outcomes.

Microsoft Graph and the az CLI

For automation, bulk lookups, or when the portal is slow, query the sign-in logs via Microsoft Graph (/auditLogs/signIns). The CA detail rides along in appliedConditionalAccessPolicies.

# All failed-CA sign-ins for one user in the last day (Graph via az rest)
az rest --method get \
  --uri "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=userPrincipalName eq 'aisha@contoso.com' and conditionalAccessStatus eq 'failure'&\$top=20" \
  --query "value[].{time:createdDateTime, app:appDisplayName, status:status.errorCode, reason:status.failureReason, client:clientAppUsed}" -o table
# Drill into ONE sign-in's applied policies (paste the id from above)
az rest --method get \
  --uri "https://graph.microsoft.com/v1.0/auditLogs/signIns/<signInId>" \
  --query "appliedConditionalAccessPolicies[].{policy:displayName, result:result, grants:enforcedGrantControls, sessions:enforcedSessionControls}" -o json

Reading sign-in logs via Graph needs AuditLog.Read.All (plus Directory.Read.All) and a directory role that can read them (Reports Reader, Security Reader, or higher). If the call 403s, that’s an RBAC problem, not a CA one — see Troubleshooting AuthorizationFailed.

KQL over SignInLogs in Log Analytics

For trends, dashboards, and alerting, export the logs to Log Analytics via a diagnostic setting (the SignInLogs table; non-interactive arrives as AADNonInteractiveUserSignInLogs). The playbook then becomes queryable:

// Which policies are blocking the most, and which app/control
SigninLogs
| where TimeGenerated > ago(7d) and ConditionalAccessStatus == "failure"
| mv-expand pol = ConditionalAccessPolicies
| where tostring(pol.result) == "failure"
| extend policyName = tostring(pol.displayName), grants = tostring(pol.enforcedGrantControls)
| summarize blocks = count() by policyName, grants, AppDisplayName
| order by blocks desc
// Report-only policies that WOULD have blocked — your pre-enforcement blast radius
SigninLogs
| where TimeGenerated > ago(7d)
| mv-expand pol = ConditionalAccessPolicies
| where tostring(pol.result) in ("reportOnlyFailure","reportOnlyInterrupted")
| summarize impacted_users = dcount(UserPrincipalName), events = count() by policyName = tostring(pol.displayName)
| order by impacted_users desc

If SignInLogs is empty even though sign-ins are happening, the diagnostic setting isn’t wired up (or the workspace is wrong) — that’s an ingestion problem, covered in No Logs Showing Up?, and you should set up the workspace first per How to Create a Log Analytics Workspace.

Architecture at a glance

Hold one mental model and every diagnosis snaps into place: a sign-in flows through three gates in order, and Conditional Access is the second. Gate one — first-factor authentication: the user proves who they are (password, passkey, federated token); if that fails you get a 500xx error (50126 bad password, 50057 disabled, 50053 locked out) and CA never runsconditionalAccessStatus stays notApplied, your signal the problem is upstream of CA. Gate two — Conditional Access: Entra gathers the sign-in’s signals (user and groups, target resource, location/IP, device state from Intune/Entra, client app, risk score), finds every policy whose assignments match, and combines their controls. Gate three — session: once every required grant control is satisfied (and nothing says Block), a token is issued and session controls (sign-in frequency, app-enforced restrictions) shape what follows.

The diagnostic method falls out of that order: at which gate did this die, and why? notApplied + a 500xx code = gate one, not a CA problem. failure = gate two, and the appliedConditionalAccessPolicies array names the policy while enforcedGrantControls names the control (Block = hard deny; Mfa/CompliantDevice/RequireAppProtection = a require the user didn’t meet). A re-prompt every hour with no error = gate three. The logs split into interactive / non-interactive / service-principal tabs because the same three gates apply to background refreshes and app-only sign-ins, not just humans — so when an app “just stops” silently, look at the non-interactive or service-principal tab for a gate-two or gate-three block the user never saw. Localise to the gate, read the field, apply the fix.

Real-world scenario

Northwind Logistics runs a 2,400-seat Entra tenant (P1, with P2 for the admin tier) governing Microsoft 365, a custom dispatch app, and a fleet-tracking SaaS. The identity team is three people; they had recently shipped a tightened Conditional Access baseline — Require MFA for all users, Block legacy authentication, and Require compliant device for the dispatch app — moving each from report-only to enforced over a fortnight.

The incident began on a Monday after a long weekend: 40 tickets before 09:30, all variations of “can’t get into email” and “the dispatch app blocked me.” Two distinct populations, but the tickets read identically because every user just saw the grey block page with a request ID. The on-call engineer’s first instinct was to suspect the newest policy — Require compliant device — and his hand hovered over the toggle. Instead he grabbed one request ID and found the matching sign-in.

That first event told a clear story: Status = Failure, Conditional Access = Failure, error 53003, and on the Conditional Access tab a single policy in failureBlock legacy authentication — with enforcedGrantControls = [Block] and Client app = “Other clients”. Not the new compliant-device policy at all. A KQL query filtered to ClientAppUsed in ("Other clients","IMAP4","Authenticated SMTP") returned 31 of the 40 — all on an old third-party mail app that still used IMAP basic auth, which had pushed a weekend update reverting a subset of accounts to legacy auth. The block was correct; the trigger was a client regression.

The other 9 showed a different code: 53000device not compliant — for the dispatch app. Device info showed isCompliant = false, yet Intune showed those devices as compliant. A sync lag: a Friday-evening compliance change hadn’t propagated the new compliant state to Entra for devices that were off all weekend. A forced Intune sync (and, for a few, waiting for the next evaluation) cleared all nine without touching a policy.

The fix landed in two tracks, and crucially no policy was loosened. For the 31: roll the third-party app back to its modern-auth version and re-authenticate with OAuth — the block policy stayed exactly as it was, because it had done its job. For the 9: a forced device sync, plus a standing alert on ResultType == 53000 so the next sync-lag wave is caught in minutes. The note on the wall afterward: “A block page is a request ID, not a diagnosis. Read the code before you reach for a toggle — 53003 and 53000 are completely different days.” From first ticket to all-clear: 70 minutes. Disabling the newest policy would have taken the dispatch app down and still not fixed the email blocks.

The incident as a timeline, because the order of moves is the lesson:

Time Symptom Action taken Effect What it should have been
09:15 40 “I’m blocked” tickets (alerts/escalation) Don’t assume the newest policy
09:20 Hand on the compliant-device toggle Paused No change Read one real sign-in first
09:25 First request ID matched to a sign-in Read code: 53003, legacy auth Root cause #1 found This is the breakthrough
09:35 KQL on ClientAppUsed 31 of 40 are legacy-auth Population #1 scoped
09:45 Remaining 9 read Code 53000, device not compliant Root cause #2 (sync lag) Two causes, not one
10:05 Mitigated App rollback + forced Intune sync Both populations clear No policy loosened
+1 day Hardened Standing alerts on 53003/53000 by app Next wave caught in minutes The durable fix

Advantages and disadvantages

The signals-driven, log-everything model both causes this class of ticket and makes it diagnosable. Weigh it honestly:

Advantages (why this model helps you) Disadvantages (why it bites)
Every policy evaluation is recorded per sign-in (appliedConditionalAccessPolicies) — you rarely lack data The user-facing block page is deliberately opaque; the reason lives elsewhere, so users can’t self-diagnose
What If lets you simulate scope without a real sign-in — test before you ship What If reflects policy logic, not the user’s live MFA/device state — it can mislead if you forget that
Report-only mode predicts the blast radius before enforcement — no surprise ticket flood Skipping report-only is easy and turns a rollout into an incident
Grant controls combine with AND across policies, giving precise layered security “I have MFA, why am I blocked?” — a different policy’s compliant-device/Block control denied it; the interaction is non-obvious
Failure-reason codes (53003, 53000, 50074) map cleanly to a fix category The codes are easy to confuse; 53003 covers both hard Block and unmet require controls
Logs split by sign-in type (interactive / non-interactive / SP) so app-only and background blocks are visible Searching only the Interactive tab hides non-interactive and service-principal blocks — a classic dead end
Standing exclusions and trusted locations give legitimate escape valves Those same exclusions silently create coverage gaps (scope-out) auditors later find

The model is right for any organisation that wants policy-driven, auditable access decisions instead of static rules. It bites hardest right after a new policy ships (a wave of reportOnlyFailure-turned-real blocks), for chatty non-interactive workloads (session-frequency re-auth a background process can’t do), and for anyone who confuses an MFA interrupt with a block. Every disadvantage is manageable — but only if you read the log instead of the block page, which is the entire point of this article.

Hands-on lab

Create a deliberately blocking Conditional Access policy in report-only first, watch it predict a block, enforce it, trigger the block, then read the sign-in log to diagnose it — all reversible, no spend beyond an Entra ID P1 trial. Use a test user you don’t mind locking out of one app; never test on yourself or a break-glass account.

Step 1 — Pick a disposable test user and confirm baseline. In Entra → Users, note a test account (e.g. latency-test@yourtenant.onmicrosoft.com). Sign in as them to a target app (use the My Apps portal or Office) and confirm it works today.

Step 2 — Create a Block policy in report-only. Entra → Conditional Access → Create new policy.

# Confirm the policy exists and is report-only (Graph via az rest)
az rest --method get \
  --uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies?\$filter=startswith(displayName,'LAB')" \
  --query "value[].{name:displayName, state:state}" -o table

Expected: a row with state = enabledForReportingButNotEnforced.

Step 3 — Generate a sign-in and read the report-only result. Sign in as the test user to the target app again — it still works (report-only doesn’t enforce). Now in Sign-in logs, find that event → Conditional Access tab. Expected: the LAB policy shows reportOnlyFailure — Entra is telling you it would have blocked. This is the blast-radius preview the real world skips at its peril.

// See the report-only "would-block" in Log Analytics (if diagnostic settings are on)
SigninLogs
| where TimeGenerated > ago(1h) and UserPrincipalName has "latency-test"
| mv-expand pol = ConditionalAccessPolicies
| where tostring(pol.displayName) startswith "LAB"
| project TimeGenerated, result = tostring(pol.result), grants = tostring(pol.enforcedGrantControls)

Step 4 — Confirm scope with What If (no sign-in needed). Conditional Access → What If → pick the test user and the same app → What If. Expected: the LAB policy appears under policies that would apply, with grant control Block. Try a different user in What If — the policy should not apply (proving your scope is tight).

Step 5 — Enforce and trigger the real block. Edit the LAB policy → Enable policy: On → Save. Sign in as the test user to the target app again. Expected: the grey block page with a request ID.

Step 6 — Diagnose it from the log. In Sign-in logs, find the new failed event:

# Pull the test user's latest failed-CA sign-in and its applied policies
az rest --method get \
  --uri "https://graph.microsoft.com/v1.0/auditLogs/signIns?\$filter=userPrincipalName eq 'latency-test@yourtenant.onmicrosoft.com' and conditionalAccessStatus eq 'failure'&\$top=1" \
  --query "value[0].{code:status.errorCode, reason:status.failureReason, policies:appliedConditionalAccessPolicies[?result=='failure'].{p:displayName, g:enforcedGrantControls}}" -o json

Expected: code = 53003, and one policy (LAB - …) with enforcedGrantControls = ["Block"]. You just walked the full path: a block page → its sign-in event → the 53003 code → the exact policy and the Block control. That is the entire method on one user you control.

Validation checklist. You created a Block policy in report-only, saw reportOnlyFailure predict the block, confirmed scope with What If, enforced it, reproduced the grey page, and read 53003 + the Block grant from the log. The lab steps mapped to what each proves:

Step What you did What it proves Real-world analogue
3 Read reportOnlyFailure Report-only previews blocks without blocking Every safe rollout
4 What If on two users Scope is testable before a real sign-in Pre-flighting a new policy
5 Enforce, get the grey page Enforcement is what the user actually hits The ticket itself
6 Read 53003 + Block from the log The block page → the diagnosis The 90-second triage

Cleanup (remove the lab policy so it can’t block anyone).

# Delete the LAB policy by id (get the id from Step 2's query, then:)
az rest --method delete \
  --uri "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/<policyId>"

Or delete it in the portal (Conditional Access → the LAB policy → Delete). Verify the test user can sign in to the app again.

Cost note. Conditional Access needs Entra ID P1 (a free trial covers the lab); there is no per-policy or per-evaluation charge. The only “cost” is the Log Analytics ingestion if you export SignInLogs — trivial for a lab, and you can skip the diagnostic setting and use the portal logs instead.

Common mistakes & troubleshooting

This is the playbook — the part you bookmark. First as a scannable table you can read while a user waits on the phone, then the same entries with the full confirm-command detail underneath. It spans the basic blocks (legacy auth, MFA) and the advanced ones (device sync lag, non-interactive re-auth, workload identity, stale exclusions).

# Symptom Root cause Confirm (exact cmd / portal path) Fix
1 User blocked, but “I have MFA!” A different applicable policy required a compliant device or Block — grants AND across policies Sign-in → CA tab → find the failure policy’s enforcedGrantControls Satisfy that control (compliance), or scope that policy
2 Old mail client / printer flat-denied Block legacy authentication matched (“Other clients”) Additional details → Client app; KQL ClientAppUsed in ("Other clients",...) Move client to modern auth; never just exclude it
3 “Blocked” but it’s a wrong password Not CA at all — conditionalAccessStatus = notApplied, error 50126 Sign-in → Status + code; CA = Not applied Reset password / unlock; CA is innocent
4 Device worked yesterday, 53000 today Compliant state drifted, or Intune→Entra sync lag Device info isCompliant=false vs Intune (compliant) Force Intune sync / wait an eval; remediate real failures
5 App “just stops”, no prompt, no error users see Non-interactive token refresh blocked (session frequency / revoked) Sign-in logs → Non-interactive tab; ResultType there Re-auth interactively; review sign-in-frequency policy
6 Service/app integration suddenly 403/blocked Workload identity CA policy on the service principal Sign-in logs → Service principal tab Adjust the workload-identity policy; use proper flow
7 MFA prompt appears but user can’t pass it No usable method registered (50079/53004) Authentication methods → registration details Register Authenticator/FIDO2/phone; run a campaign
8 Intermittent block, only from certain places Location condition (untrusted country / VPN egress) Location tab + Named locations; KQL on country Add trusted location, or base on trusted IP ranges
9 Policy you built isn’t stopping anyone Scope-out: user excluded, trusted location, or not in include set CA tab → result=notApplied + conditions; What If Fix the exclusion / include set; re-test in What If
10 New policy caused a ticket flood on go-live Enforced without report-only first Report-only reportOnlyFailure count (had you checked) Roll back to report-only; size impact; re-enforce
11 Linux/Chromebook user blocked from one app Device platform condition with Block Device info → OS; CA tab platform condition Allow the platform if needed, or scope the policy
12 Mobile user blocked from Exchange/SharePoint Require approved app / app protection not met (53002) Additional details → client app Move to Outlook/approved app with APP policy applied
13 “Strong auth required” loop, never resolves Authentication strength (phishing-resistant) unmet Policy → auth strength; Authentication details Register passkey/FIDO2/CBA method
14 Block traced to a policy nobody remembers editing Group membership change pulled the user into scope CA tab → the policy’s group assignment; group audit Adjust group membership or the policy’s include set
15 Graph/log query returns 403, not the sign-in RBAC — caller lacks AuditLog.Read.All / reader role The 403 body; az ad signed-in-user show roles Grant Reports/Security Reader + the Graph permission

The expanded form, with the full reasoning for the entries that bite hardest:

1. “I have MFA, why am I blocked?” Root cause: MFA satisfied one policy, but a second applicable policy required something else — most often a compliant device or an outright Block — and grant controls combine with AND across all applicable policies, so one unmet control anywhere blocks the whole sign-in. Confirm: Sign-in event → Conditional Access tab → find the row with result = failure (it won’t be the MFA one) and read its enforcedGrantControls. Fix: Satisfy that control (e.g. make the device compliant), or — if the second policy shouldn’t apply here — fix its scope. Never assume the user’s own MFA status explains a block.

2. An old mail client or device is flatly denied. Block legacy authentication matched because the client shows as “Other clients” (IMAP/POP/SMTP/EAS), which can’t do interactive MFA. Additional details → Client app confirms it; the KQL above lists the whole affected population. Move the client to modern auth — do not exclude it, which re-opens the password-spray surface the policy closes.

3. “Blocked” that’s actually a bad password or locked account. It isn’t Conditional Access: first-factor auth failed before CA ran, so conditionalAccessStatus = notApplied and the code is a 500xx (50126 wrong password, 50053 locked out, 50057 disabled). Reset/unlock the account — the giveaway is notApplied + a 500xx code, not a policy.

4. A device that worked yesterday is blocked with 53000 today. Root cause: Require compliant device is unmet because the device drifted out of compliance, or Intune marked it compliant but that state hadn’t synced to Entra at sign-in time (common after a weekend or a compliance-policy change). Confirm: Device info tab shows isCompliant = false, while Intune → the device → Compliance may show compliant (the sync-lag tell) or reveal the failing setting. Fix: If Intune already shows compliant, force a device sync / wait for the next evaluation. If a setting genuinely fails (encryption, OS version), remediate it. Scope the policy only if the device should be legitimately exempt.

5. An app “just stops working” with no prompt the user ever sees. Root cause: The block is on a non-interactive sign-in — a silent token refresh that a sign-in-frequency session control forced to re-authenticate (which a background process can’t do), or a revoked/expired session being re-evaluated. Confirm: Sign-in logs → Non-interactive user sign-ins tab (the Interactive tab will show nothing) and read the ConditionalAccessStatus/ResultType there. Fix: Have the user re-authenticate interactively to mint a fresh token; review whether the sign-in-frequency policy should apply to that app/flow at all.

6. A service or app integration suddenly returns 403 / is blocked. Root cause: A Conditional Access policy for workload identities is governing the service principal (app-only / client-credentials) sign-in — a newer capability that blocks or location-restricts app-only access. Confirm: Sign-in logs → Service principal sign-ins tab; the appliedConditionalAccessPolicies there name the workload-identity policy. Fix: Adjust the workload-identity policy (e.g. add the source IP to a trusted location, or scope the SP out if appropriate). Confirm the integration uses the correct OAuth flow.

7. The MFA prompt appears but the user can never pass it. They have no usable MFA method registered (codes 50079/53004), so a Require MFA policy can’t be satisfied. Entra → Authentication methods → User registration details (or the userRegistrationDetails Graph API) confirms no method. Register one — Authenticator, FIDO2/passkey, or phone — via a registration campaign so you catch the whole unregistered population, not one user at a time.

8. Blocks only from certain places. A location condition (untrusted country, or an IP outside your trusted ranges via VPN/travel) scopes a Block or step-up policy in. The Location tab shows the source and named-location match. Add the legitimate location as trusted, or base the condition on trusted IP ranges rather than fallible GeoIP — don’t disable the policy.

9. A policy you carefully built isn’t blocking anyone (scope-out). The user (or their group) is excluded, the sign-in is from an excluded trusted location, a device filter excluded the device, or they’re not in the include set. The policy’s row shows result = notApplied; What If states the exclusion reason explicitly. Correct the exclusion/include set and re-validate — this is the audit that proves a high-value app is actually covered.

10. A new policy caused a flood of blocks on go-live. It was enforced without a report-only soak, so its blast radius (unregistered users, non-compliant devices, legacy clients) hit production at once. Roll it back to report-only, size the impact (reportOnlyFailure count by policy), remediate, then re-enforce — the discipline in Deploying Conditional Access Safely.

14. A block traces to a policy nobody remembers changing. The policy didn’t change — the user’s group membership did, pulling them into scope (often a nested or dynamic group whose rule started matching them). Check the failure policy’s group assignment and the user’s membership/membershipRule. Fix the membership or rule if wrong; otherwise the user is now correctly in scope. The dynamic groups cookbook covers rules that don’t surprise you.

15. Your own query for the sign-in returns 403. Not a CA problem — you lack permission to read sign-in logs. Graph needs AuditLog.Read.All plus a reader role (Reports Reader, Security Reader, or higher); the 403 body names the missing permission. The method for reading your own effective permissions is in Troubleshooting AuthorizationFailed.

Best practices

The alerts worth wiring before the next incident — leading indicators, not the lagging “user complained”:

Alert on Signal (KQL field) Threshold (starting point) Why it’s leading
Legacy-auth blocks ClientAppUsed legacy + ResultType 53003 Any sustained, or a sudden spike A client regression or spray attempt
Device-compliance blocks ResultType == 53000 Spike vs baseline Sync lag or a bad compliance push
MFA-unregistered failures ResultType in (50079,53004) > 0 for active users A population that will be locked out when you enforce
Report-only would-block result == "reportOnlyFailure" dcount(users) before enforcing The pre-enforcement blast radius
Block-control denials by policy ResultType 53003 grouped by policy Spike on any one policy A scope change or new client population
Workload-identity blocks Service-principal tab failures Any new occurrence A service integration just broke

Security notes

Cost & sizing

Conditional Access is a licensing line, not a metered one — the levers are licences and the log pipeline, and “sizing” means access tier and log retention, not instances.

A rough monthly picture for a 2,000-seat tenant already on M365 E3/E5: CA itself adds nothing beyond the suite licence; the only incremental spend is Log Analytics ingestion for the sign-in tables — often a few hundred to a couple of thousand rupees a month, driven by whether you export the chatty non-interactive table and how long you keep it. The cost drivers and what each buys you:

Cost driver What you pay for Rough scale What it buys Watch-out
Entra ID P1 (per user) Conditional Access, What If, report-only Bundled in M365 E3 All non-risk CA No risk-based conditions on P1
Entra ID P2 (per user) Risk conditions, Identity Protection, PIM Bundled in M365 E5 Risk-based CA, JIT roles Only needed where you use risk/PIM
SignInLogs ingestion Interactive sign-in log GB Modest Queryable interactive blocks Per-GB; grows with tenant size
Non-interactive log ingestion Token-refresh log GB Large Visibility into silent blocks Can dwarf interactive volume — export deliberately
Log Analytics retention GB-months beyond free Your choice Longer investigation/audit window “Forever” retention is a real bill

Interview & exam questions

1. A user is blocked and insists “but I have MFA.” What’s the most likely explanation and how do you confirm it? Grant controls combine with AND across all applicable policies, so MFA satisfied one policy while a different applicable policy required something the user didn’t meet — commonly a compliant device or an outright Block. Confirm on the sign-in event’s Conditional Access tab: find the policy whose result is failure (it won’t be the MFA one) and read its enforcedGrantControls.

2. What is the difference between conditionalAccessStatus values failure and notApplied? failure means at least one applicable policy’s required control was not satisfied (a block or unmet grant) — a genuine CA outcome. notApplied means no policy’s assignments matched this sign-in, so CA did nothing; if the sign-in still failed, it failed for a non-CA reason (e.g. a 500xx auth error before CA ran).

3. A user reports “Conditional Access blocked me” but the sign-in shows error 50126. Is it a CA problem? No. 50126 is invalid username or password — a first-factor authentication failure that happens before Conditional Access evaluates, so conditionalAccessStatus is notApplied. The fix is a password reset/unlock; looking at policies wastes time. The tell is notApplied + a 500xx code.

4. Which field names every policy that was evaluated for a sign-in, and what does its result of failure mean? The appliedConditionalAccessPolicies array (the Conditional Access tab in the portal). A result of failure for a policy means that policy applied and one of its required controls was not satisfied — read enforcedGrantControls to see whether it was a hard Block or a require (MFA, compliant device, app protection) the user could meet.

5. What does error code 53003 tell you, and what does it not tell you? 53003 means access was blocked by Conditional Access — a grant control denied the sign-in. It does not by itself distinguish a hard Block access control from an unmet require control (MFA/compliant device); for that you must read the enforcedGrantControls of the failure policy. Block is a hard deny; a require is something the user can satisfy.

6. A scheduled integration suddenly starts failing with a block, but the user-interactive sign-in logs show nothing. Where do you look? The Non-interactive user sign-ins or Service principal sign-ins tab. A background token refresh blocked by a sign-in-frequency session control appears under non-interactive; an app-only (client-credentials) sign-in governed by a workload-identity Conditional Access policy appears under service principal. Searching only Interactive sign-ins is the classic dead end.

7. How do you predict which users a new blocking policy will affect before enforcing it? Deploy the policy in report-only mode and watch the appliedConditionalAccessPolicies results for reportOnlyFailure/reportOnlyInterrupted over a full business cycle, ideally via KQL over SignInLogs (count distinct users impacted by policy). Complement with the What If tool to validate scope for specific users. Never enforce a new blocking policy without one of these.

8. What is the limitation of the What If tool that catches people out? What If evaluates policy logic only — which policies would apply to a hypothetical sign-in and why — but it does not know the user’s live state (actual MFA registration, real device compliance). It will say “Require compliant device would apply” without knowing whether the device is compliant right now. For real outcomes you still read an actual sign-in or check Intune.

9. A device worked yesterday and is blocked with 53000 today, yet Intune shows it as compliant. What’s happening? A compliance state sync lag between Intune and Entra: the device became (or was re-marked) compliant in Intune, but that state hadn’t propagated to Entra at sign-in time — common after a weekend or a compliance-policy change. Confirm by comparing the sign-in’s isCompliant=false against Intune’s compliant status; fix with a forced device sync or by waiting for the next evaluation, not by editing the policy.

10. Why is excluding a user from a Block legacy authentication policy a bad fix, and what should you do instead? Excluding them re-opens the basic-auth attack surface (legacy protocols can’t do interactive MFA and are a primary password-spray vector) — a security regression to fix a usability ticket. The right fix is to move the client to modern authentication (OAuth); if a service truly can’t, scope the exception to a single documented, owned, time-boxed identity, ideally a workload identity.

11. What grant control combination makes “require one of MFA or compliant device” possible, and how does that differ across two policies? Within one policy, selecting both controls with “Require one of the selected controls” lets either satisfy it. Across two separate policies, controls are ANDed — the user must meet both policies’ requirements — so you cannot express “either/or” by splitting controls into two policies; you must put the “or” inside a single policy.

12. Where do you go first when a sign-in event itself returns 403 to your Graph query for it? That’s an RBAC problem, not a Conditional Access one: reading sign-in logs via Graph needs AuditLog.Read.All and a directory role such as Reports Reader or Security Reader. The 403 body names the missing permission. Grant least-privilege read access rather than escalating to Global Administrator.

These map to SC-300 (Identity and Access Administrator)plan, implement and manage Conditional Access, sign-in diagnostics, Identity Protection — and AZ-500 (Security Engineer)manage identity and access, Conditional Access, MFA. The reporting/log angle also touches SC-200. A compact cert-mapping for revision:

Question theme Primary cert Exam objective area
CA policy logic, grant control combination SC-300 Plan & implement Conditional Access
Reading sign-in logs, failure codes SC-300 / SC-200 Monitor identity; investigate sign-ins
Report-only, What If, blast-radius sizing SC-300 Implement & manage CA safely
Device-compliance & app-protection grants SC-300 / MD-102 Conditional Access with Intune signals
Legacy-auth blocking, MFA strength SC-300 / AZ-500 Secure authentication; MFA
Least-privilege log access (RBAC/Graph) AZ-500 / SC-300 Manage identity & access

Quick check

  1. A user is blocked and says “but I have MFA.” Which field do you read to find the actual control that denied them, and why isn’t it the MFA policy?
  2. A sign-in shows conditionalAccessStatus = notApplied and error 50126. Is this a Conditional Access block? What’s the fix?
  3. What does error code 53003 tell you, and what crucial detail must you still read to know whether it was a hard block or a satisfiable require?
  4. An app integration silently stops working with no prompt the user sees, and the Interactive sign-in logs show nothing. Name two tabs to check.
  5. You’re about to enforce a new blocking policy. What mode do you use first, and which result value tells you the blast radius?

Answers

  1. Read the appliedConditionalAccessPolicies array (the Conditional Access tab) and find the policy whose result is failure — then read its enforcedGrantControls. It isn’t the MFA policy because grant controls AND across all applicable policies, so MFA satisfied one policy while a different one (commonly compliant device or Block) was the one that denied access.
  2. No50126 is an invalid username/password, a first-factor failure that happens before CA runs, which is why conditionalAccessStatus is notApplied. The fix is a password reset / account unlock, not a policy change.
  3. 53003 means access was blocked by Conditional Access (a grant control denied it). You must still read the failure policy’s enforcedGrantControls: a Block is a hard deny, whereas Mfa/CompliantDevice/RequireAppProtection is a require the user can satisfy.
  4. The Non-interactive user sign-ins tab (a background token refresh blocked by a sign-in-frequency control) and the Service principal sign-ins tab (an app-only sign-in governed by a workload-identity policy).
  5. Deploy it in report-only mode first; the reportOnlyFailure (and reportOnlyInterrupted) results — countable by distinct users over a business cycle — are your pre-enforcement blast radius.

Glossary

Next steps

You can now turn a grey block page into a precise diagnosis. Build outward:

Entra IDConditional AccessSign-In LogsTroubleshootingMFAIdentityKQLAzure AD
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading