Find the Conditional Access Policy Blocking a User Sign-In
For developers and support engineers dealing with a user who cannot sign in because Conditional Access blocked them, but the blocking policy is unclear. This runbook shows the fastest ways to identify the exact policy from sign-in logs, correlation IDs, and policy report output, then fix the underlying assignment or condition mismatch.
TL;DR — When a user is blocked by Conditional Access and nobody can tell which policy did it, start with the failed sign-in event and inspect the Conditional Access policy evaluation on that single event. The most common outcome is a broad "block" policy or an unexpected condition match from location, device state, or app scope; the fastest fix is usually narrowing assignments or excluding the affected break-glass/test path. Reading time: ~6 min
The scenario
It is 3:17 PM on a Tuesday and a developer pings you: one user cannot get into Microsoft 365 or your SSO-backed internal app, but everyone else can. The user gets bounced back to the sign-in page with a generic access-denied message, the helpdesk has already tried password reset, and the identity admin says, "I can see Conditional Access blocked it, but I can't tell which policy." You have a correlation ID from the error page, a timestamp, and an impatient manager asking whether this is a rollout regression. You need the exact policy name, not another hour of guessing through policy lists.
Symptoms
- User sees one of these messages during sign-in:
You can't get there from here. Your sign-in was successful but does not meet the criteria to access this resource. - Or the app returns an OAuth/OIDC failure after redirect:
error=access_denied error_description=AADSTS53003: Access has been blocked by Conditional Access policies. - Common tenant-side sign-in failure codes/messages:
AADSTS53003: Access has been blocked by Conditional Access policies. AADSTS53000: Device is not in required device state. AADSTS50131: Conditional Access policy requires a compliant device. AADSTS50097: Device authentication is required. - Sign-in log entry shows failure with Conditional Access status similar to:
Status: Failure Conditional Access: Failure Failure reason: Access has been blocked due to Conditional Access policies. - The sign-in event has a correlation/request ID and timestamp, but the blocking policy is not obvious from the main event list.
- The user may succeed from one network/device but fail from another, which usually points to location or device filters rather than credentials.
Likely causes
| Cause | How common | Quick check |
|---|---|---|
| Broad block policy matched the user/app unexpectedly | Very common | Open the failed sign-in event and inspect the Conditional Access tab/details for policies with result failure or block |
| Named location / IP condition matched incorrectly | Common | Reproduce from a different network or compare the sign-in event IP against your named locations list |
| Device compliance / hybrid join requirement not met | Common | Check the failed sign-in event for device state/compliance details and failure code AADSTS50131, AADSTS53000, or AADSTS50097 |
| Policy scoped to the wrong cloud app / enterprise app | Common | In the failed sign-in event, inspect the target resource/app and matched policy assignments |
| User/group assignment drift or nested-group misunderstanding | Medium | Compare the user's direct/effective group membership with the policy's included/excluded groups |
| Report-only vs enabled policy confusion / stale assumptions | Medium | In the policy list, check the policy state and the sign-in event's per-policy result rather than the policy name alone |
Step-by-step diagnosis
-
Find the exact failed sign-in event.
- Use your identity provider's sign-in logs and filter by the user's UPN, the failure timestamp, and the correlation/request ID from the error page.
- If you have CLI/API access, query sign-in logs around the timestamp. With Microsoft Graph PowerShell:
Connect-MgGraph -Scopes "AuditLog.Read.All","Policy.Read.All","Directory.Read.All" $upn = "user@contoso.com" Get-MgAuditLogSignIn -Filter "userPrincipalName eq '$upn'" -Top 10 | Select-Object CreatedDateTime,AppDisplayName,Status,ConditionalAccessStatus,CorrelationId- This is your problem if you see a failed event with
ConditionalAccessStatusset tofailureand the timestamp matches the incident. - Jump to step 2.
-
Open policy evaluation on that single event.
- In the sign-in event details, open the Conditional Access section/tab/details. Do not start from the policy list; start from the event.
- API shape to inspect the event payload if your tooling exposes raw JSON:
{ "conditionalAccessStatus": "failure", "appliedConditionalAccessPolicies": [ { "displayName": "Block legacy auth", "result": "notApplied" }, { "displayName": "Require compliant device for M365", "result": "failure" } ] }- This is your problem if one or more policies show
failureorblock, or if a grant control was not satisfied. - If you have a single obvious failed policy, jump to the matching fix section.
- If multiple policies appear, continue to step 3.
-
Check whether the block is from location, device, or app scope.
- In the same event, inspect these fields: user, app/resource, client app, IP address, device ID, join/compliance state, platform, and location.
- Typical clues:
IP address: 203.0.113.44 Resource: Office 365 Exchange Online Device ID: <empty> Join type: Unregistered Compliant: No Client app: Browser- If IP/location looks wrong or the user succeeds from mobile hotspot/VPN-off, jump to "Named location / IP condition matched incorrectly".
- If device is unregistered/noncompliant or the failure code is
AADSTS50131,AADSTS53000, orAADSTS50097, jump to "Device compliance / hybrid join requirement not met". - If the target app/resource is not what the policy author intended, jump to "Policy scoped to the wrong cloud app / enterprise app".
-
Validate user and group targeting.
- Compare the user's direct and effective group membership with the policy include/exclude assignments.
- Graph PowerShell examples:
$userId = (Get-MgUser -UserId "user@contoso.com").Id Get-MgUserTransitiveMemberOf -UserId $userId -All | Select-Object Id,AdditionalProperties- This is your problem if the user is in an included group you did not expect, or is missing an exclusion group you assumed was inherited.
- Jump to "User/group assignment drift or nested-group misunderstanding".
-
Verify policy state and avoid report-only confusion.
- Open the policy itself and check whether it is enabled, disabled, or report-only. Then compare that with the sign-in event's per-policy result.
- This is your problem if responders are blaming a report-only policy or ignoring an enabled policy with the same-looking scope.
- Jump to "Report-only vs enabled policy confusion / stale assumptions".
-
Reproduce safely with a test user if needed.
- Use a non-privileged test account placed into the same groups and reproduce from the same network/device class.
- Confirm the same app, same client type, and same IP path. If the policy only triggers in one path, that narrows the condition immediately.
- Jump to the fix matching the condition that reproduces.
Fixes
Broad block policy matched the user/app unexpectedly
- Edit the policy assignments and narrow one dimension at a time: users/groups, target apps, client apps, locations, or device filters.
- Typical remediation pattern: replace tenant-wide include with a specific group, then add an exclusion group for emergency/test accounts.
- If using Graph or automation, update the policy JSON rather than hand-editing multiple screens. Example shape:
{
"conditions": {
"users": {
"includeGroups": ["<prod-users-group-id>"],
"excludeGroups": ["<breakglass-group-id>"]
},
"applications": {
"includeApplications": ["Office365"]
}
},
"grantControls": {
"operator": "OR",
"builtInControls": ["mfa"]
}
}
- Verify it worked: repeat the sign-in and confirm the event no longer lists that policy with result
failure.
Named location / IP condition matched incorrectly
- Compare the event IP with your named locations and trusted ranges. Fix the CIDR, remove stale office/VPN ranges, or stop keying policy decisions off an egress IP that changed.
- Quick CIDR sanity check locally:
python3 - <<'PY'
import ipaddress
ip = ipaddress.ip_address('203.0.113.44')
for cidr in ['203.0.113.0/24','198.51.100.0/24']:
print(cidr, ip in ipaddress.ip_network(cidr))
PY
- If the user is behind split-tunnel VPN, test with VPN off and on; many false positives come from traffic exiting an unexpected gateway.
- Verify it worked: the new sign-in event shows the correct location classification and the location-based policy result changes from
failuretonotAppliedorsuccess.
Device compliance / hybrid join requirement not met
- If the policy requires a compliant or hybrid-joined device, the fix is on the device state, not the user account.
- On Windows, confirm join state:
Dsregcmd /status
- Problem indicators in output:
AzureAdJoined : NO
DomainJoined : NO
DeviceAuthStatus : FAILED
- Remediate by enrolling/registering the device in your endpoint management flow or by moving the user to a policy path that only requires MFA for the affected app while device onboarding is completed.
- Trade-off: relaxing a device requirement to restore access is a security downgrade; prefer a temporary exclusion on a tightly scoped group with an expiry.
- Verify it worked:
Dsregcmd /statusshows the expected joined state and the next sign-in no longer fails withAADSTS50131,AADSTS53000, orAADSTS50097.
Policy scoped to the wrong cloud app / enterprise app
- Open the failed event and note the exact resource/app display name and app ID. Then compare it with the policy's target apps.
- Common mistake: policy intended for one enterprise app also includes a broader app suite or "all cloud apps".
- Remediate by changing target apps to the exact app IDs or app objects you intend, then save and retest.
- Verify it worked: the failed app is no longer listed under the policy's targeted resources, and the sign-in succeeds or is evaluated by the correct policy.
User/group assignment drift or nested-group misunderstanding
- Add or remove the user from the correct assignment groups explicitly; do not assume nested groups are evaluated the way your team expects without checking effective membership.
- Graph PowerShell examples:
# Add user to exclusion group
New-MgGroupMemberByRef -GroupId "<exclude-group-id>" -BodyParameter @{"@odata.id"="https://graph.microsoft.com/v1.0/directoryObjects/<user-id>"}
- If your process relies on dynamic groups, wait for membership processing before retesting.
- Verify it worked: the user's effective membership reflects the intended include/exclude set and the sign-in event shows the policy result changed.
Report-only vs enabled policy confusion / stale assumptions
- Stop comparing policy names in chat screenshots; compare the event's per-policy result and the current policy state in the admin UI or via API.
- If there are duplicate policies with similar names, rename them to include state/scope, for example:
CA - M365 - Require Compliant Device - ENABLED
CA - M365 - Require Compliant Device - REPORT ONLY
- If automation manages policies, pull current state from source of truth and redeploy to remove drift.
- Verify it worked: responders can identify one enabled policy as the blocker from the sign-in event without ambiguity.
Prevention
- Add a sign-in triage checklist to incident templates: require
user,timestamp,correlation ID,app/resource,IP, anddevice statebefore escalation.
Required fields: UPN, UTC timestamp, correlation ID, app name, source IP, device joined/compliant state
- Enforce naming conventions on Conditional Access policies so the scope is visible in the name.
CA - <apps> - <control> - <audience> - <state>
Example: CA - Exchange Online - Require MFA - Employees - ENABLED
- Keep one emergency access path excluded from broad user-targeted policies, and review it quarterly.
⚠️ Do not exclude privileged admin groups broadly; use dedicated break-glass accounts with strong monitoring.
- Before enabling a new policy, run it in report-only mode long enough to collect real sign-in matches, then review the event-level policy results for false positives.
- Export sign-in logs to your SIEM and alert on spikes of these failure codes:
AADSTS53003
AADSTS53000
AADSTS50131
AADSTS50097
- Put policy definitions in version control if you automate them. Validate include/exclude groups, app targets, and named-location CIDRs in CI with schema checks and peer review before rollout.
{
"checks": [
"no policy with includeUsers=All and grant=block without explicit exclusions",
"all named locations must be valid CIDR",
"report-only and enabled policies must not share identical names"
]
}
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI