A decision tree for the second most common M365 ticket after missing email. The sign-in log almost always contains the answer; the skill is reading it in the right order. Most sign-in cases resolve at Step 2 or 3.
"Can't sign in" is a symptom shared by at least five different problem families: wrong credentials, MFA trouble, Conditional Access blocks, device state, and application misconfiguration. Guessing between them wastes time; the failed sign-in event tells you which family you are in via its error code. Everything below is built around getting that code and branching on it.
Pin down four things: the exact UPN, roughly when the failure happened, what the user was signing in to (Outlook desktop, Teams, browser, phone), and the error text or screenshot if they have one. "It doesn't work" tickets become five-minute fixes once you have the AADSTS code from the screenshot alone. Paste it straight into the AADSTS decoder.
Pull the recent failures for the user. Does the failed attempt appear?
Get-MgAuditLogSignIn -Filter "userPrincipalName eq 'user@contoso.com' and status/errorCode ne 0" -Top 25 |
Select-Object CreatedDateTime, AppDisplayName, ClientAppUsed, IpAddress,
@{n='Error';e={$_.Status.ErrorCode}}, @{n='Reason';e={$_.Status.FailureReason}}
Failures appear: note the error code and the failure reason. Go to Step 2 and branch on the code.
No sign-in events at all: the request never reached Entra ID. The user may be typing the wrong address entirely, be signing in to a personal Microsoft account, have no network path, or be hitting a federated IdP that fails before Entra ID. Confirm the exact UPN and what the sign-in screen looks like.
Only successful events: the sign-in worked and the problem is after authentication: a licence or permission issue in the app itself, not a sign-in issue. Check licensing (Get-MgUserLicenseDetail) and app-level access.
Interactive sign-ins appear in the log within a few minutes. Non-interactive ones (token refreshes) are in a separate log and are rarely what the user is describing. If the timestamps look wrong, remember the log is UTC.
Match the AADSTS code family; this decides the rest of the triage:
50126, 50055, 50144, 50034 (credentials): wrong password, expired password, or wrong account. Go to Step 3.
50074, 50076, 50079, 500121, 53004 (MFA): MFA required, not registered, or failed. Go to Step 4.
53003, 50131, 530032, 70043 (Conditional Access): a policy blocked it. Go to Step 5.
53000, 53001, 53002, 50097 (device state): compliance or join requirements not met. Go to Step 6.
50105, 65001, 700016, 7000215 (application): app assignment, consent or registration problems. Go to Step 7.
50053, 50057, 50132, 50173 (blocked or revoked): lockout, disabled account, or revoked sessions. Go to Step 8, and consider whether this is a security event, not a fault.
For any code not listed, the AADSTS decoder covers 40+ codes with causes and next steps, and falls back to Microsoft's official lookup for the rest.
Is it one user mistyping, or a pattern?
One user, occasional 50126: a mistyped password. Reset it or walk them through self-service reset. Case closed.
One user, many 50126s from IPs that are not theirs: password spray against this account. Check the IPs in the log; if foreign, treat as attempted compromise and consider the incident response builder, Risky Sign-in scenario.
Synced account, password just changed: password hash sync lag. Verify sync health and force a sync cycle on the Entra Connect server.
Get-MgAuditLogSignIn -Filter "status/errorCode eq 50126" -Top 100 | Group-Object IpAddress | Sort-Object Count -Descending | Select-Object Count, Name -First 10
That second command is worth running tenant-wide occasionally: one IP failing against many accounts is the classic password-spray signature, visible in thirty seconds.
What state is the user's MFA registration in?
Get-MgUserAuthenticationMethod -UserId user@contoso.com | Select-Object Id, AdditionalProperties
50079 and no methods registered: the user never enrolled. Send them to aka.ms/mfasetup. If a CA policy blocks registration itself (53004), issue a Temporary Access Pass to bootstrap.
Methods exist but challenges fail (500121): new phone, lost device, or wrong number registered. Clear the stale method and re-register. A user denying prompts they did not start is an MFA-fatigue attack signal: the attacker has the password. Reset it.
50074 from an old client: the app cannot perform MFA (legacy protocol). The fix is a modern client, not an MFA change.
New-starter lockouts are the most common MFA ticket: they must register MFA but cannot sign in to register. A Temporary Access Pass (issued via Entra admin center or Graph) breaks that loop cleanly and expires on its own.
Something blocked the sign-in (53003). Which policy, and did it behave correctly?
Find the policy: the sign-in log entry names it. In PowerShell, expand the applied policies on the event; in the portal, open the sign-in and read the Conditional Access tab, where every policy is listed as Success, Failure or Not applied.
Get-MgAuditLogSignIn -Filter "userPrincipalName eq 'user@contoso.com'" -Top 5 | Select-Object -ExpandProperty AppliedConditionalAccessPolicies | Select-Object DisplayName, Result
The policy is right, the user is wrong: travelling user in a blocked country, VPN exit node in a blocked location, legacy client blocked by design. The fix is on the user's side (drop the VPN, use the approved client), not the policy's.
The policy caught more than intended: reproduce with the What If tool in the CA blade before editing anything. Exclusions are safer than weakening conditions.
Never fix a CA lockout by disabling the policy tenant-wide. Add a scoped exclusion, verify with What If, and re-tighten. And if the person locked out is the last Global Admin, this is why break-glass accounts exist; see the Conditional Access baseline guide.
The policy wants a compliant or joined device. What does the device actually report?
On the device: run dsregcmd /status. For hybrid join both AzureAdJoined and DomainJoined must be YES; for Entra join, AzureAdJoined alone.
In the tenant: check the device object and its compliance state:
Get-MgDeviceManagementManagedDevice -Filter "userPrincipalName eq 'user@contoso.com'" | Select-Object DeviceName, OperatingSystem, ComplianceState, LastSyncDateTime
Non-compliant (53000): the compliance detail in Intune names the failing rule, commonly encryption off, OS below minimum, or the device simply has not synced for days. Force a sync first; stale devices cure half of these.
Not joined (53001) or wrong app (53002): personal device or native mail app hitting a corporate-device policy. Working as designed; the user needs the enrolled device or the approved app (Outlook mobile, Edge).
The remote device actions (sync, compliance re-evaluation) are in the Intune builder. A device that enrolled minutes ago may honestly report non-compliant until its first evaluation completes, so wait out the first sync before digging.
The user's credentials and policies are fine; the application configuration is not.
50105 (not assigned): the enterprise app requires assignment. Assign the user or their group, or turn off the assignment requirement if the app is meant to be open.
65001 / 90094 (consent): the app needs consent that has not been granted. Review the requested scopes before an admin consents. An unfamiliar app requesting mailbox access is an OAuth-phishing pattern, not a support ticket.
7000215 (invalid client secret): the classic "the integration stopped working overnight": the app registration's client secret expired. Check the expiry, issue a new secret, and prefer certificates for automation (see the connection setup guide).
700016 (app not found): wrong tenant in the authority URL or a deleted app registration.
Application errors affect every user of the app equally. If exactly one integration or one app fails for everyone at once while normal sign-ins work, start here rather than at Step 3.
Lockouts and revocations have a reason. Find it before undoing it.
50053 (smart lockout): something is hammering the account with wrong passwords. If the source IPs are not the user, it is an attack in progress; the lockout is doing its job.
50057 (disabled): who disabled it, and why? Check the audit log before re-enabling; it may have been disabled in response to a compromise.
Get-MgAuditLogDirectoryAudit -Filter "targetResources/any(t:t/userPrincipalName eq 'user@contoso.com')" -Top 20 |
Select-Object ActivityDateTime, ActivityDisplayName, @{n='By';e={$_.InitiatedBy.User.UserPrincipalName}}
50132 / 50173 (sessions revoked): a password change or an admin revocation. Expected during incident response; if nobody remembers doing it, find out who did in the audit log.
Risk-based block (50131): check Identity Protection for the risk detail, and follow the Risky Sign-in scenario in the incident response builder.
Get the AADSTS code from the sign-in log, then branch: credential codes mean reset or spray-check; MFA codes mean registration state and a Temporary Access Pass for the stuck; CA codes mean read which policy fired and fix the user's side first; device codes mean dsregcmd and compliance detail; app codes mean assignment, consent or an expired secret; lockout codes mean find out why before unblocking. The code is the map; everything else is following it.