In this module
EI1.6 Risk Signals and Identity Protection
How Identity Protection assigns risk
Microsoft Entra ID Protection is a machine learning-based risk engine that evaluates every sign-in and every user account for suspicious behavior. It produces two independent risk assessments that appear in the sign-in logs:
Sign-in risk measures how suspicious a specific authentication attempt is. It answers the question: does this sign-in look like it came from the legitimate user, or does it look like an attacker? Sign-in risk is assessed in real time during the authentication process and is available before conditional access makes its enforcement decision. This means a risk-based conditional access policy can block or challenge a risky sign-in before access is granted.
Risk fields in the sign-in log
The sign-in log contains several risk-related fields:
RiskLevelDuringSignIn — the sign-in risk level at the time of authentication. This is the real-time assessment. Values: none, low, medium, high, hidden (risk detected but suppressed, typically in report-only scenarios). This is the field you use in detection rules to identify suspicious sign-ins.
Understanding the risk detection types
Each risk detection type corresponds to a specific suspicious pattern. The detections fall into two categories: real-time (evaluated during authentication, can influence the access decision) and offline (calculated after authentication, used for investigation and user risk assessment).
Real-time detections — evaluated during sign-in, available for conditional access decisions:
// EI1.6 — Risk detection overview for the last 7 days
// Shows which risk types are firing and at what frequency
SigninLogs
| where TimeGenerated > ago(7d)
| where RiskLevelDuringSignIn != "none" and RiskLevelDuringSignIn != ""
| extend RiskTypes = parse_json(RiskEventTypes_V2)
| mv-expand RiskType = RiskTypes
| summarize
DetectionCount = count(),
AffectedUsers = dcount(UserPrincipalName),
MostRecentDetection = max(TimeGenerated)
by RiskLevel = RiskLevelDuringSignIn,
RiskType = tostring(RiskType)
| order by DetectionCount desc
// Review: Which detection types are most common?
// High-risk detections require immediate triage
// Medium-risk detections should be reviewed daily
// Low-risk detections indicate baseline noise — tune if volume is too highTriaging risk signals with KQL
The portal's Risky Users and Risky Sign-Ins blades provide a GUI for individual triage, but at scale, KQL queries are faster and more systematic. Here are the core triage patterns:
Find all high-risk sign-ins that succeeded (the most urgent queue):
// EI1.6 — High-risk successful sign-ins — triage immediately
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0 // Successful
| where RiskLevelDuringSignIn == "high"
| project
TimeGenerated,
UserPrincipalName,
AppDisplayName,
IPAddress,
Location = strcat(tostring(LocationDetails.city), ", ",
tostring(LocationDetails.countryOrRegion)),
RiskEventTypes_V2,
ConditionalAccessStatus,
RiskDetail
| order by TimeGenerated desc
// EVERY result requires investigation
// A high-risk sign-in that succeeded means Identity Protection flagged it
// but the access was not blocked — either no risk policy enforced, or
// the user satisfied the risk policy requirement (e.g., completed MFA)// EI1.6 — Users at risk with no remediation action taken
AADRiskyUsers
| where RiskLevel in ("medium", "high")
| where RiskState == "atRisk" // Not yet remediated or dismissed
| project
RiskLastUpdatedDateTime,
UserPrincipalName,
UserDisplayName,
RiskLevel,
RiskDetail,
RiskState
| order by RiskLastUpdatedDateTime desc
// These users need action: investigate, remediate (password change + session revoke),
// or dismiss with documented justification
// The triage workflow is formalized in EI5// EI1.6 — What did risky users do after their risky sign-in?
// Correlate risky sign-in with subsequent activity
let riskySignIns = SigninLogs
| where TimeGenerated > ago(24h)
| where RiskLevelDuringSignIn in ("medium", "high")
| where ResultType == 0
| project RiskyUser = UserPrincipalName, RiskyTime = TimeGenerated, RiskyIP = IPAddress;
AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| join kind=inner riskySignIns on $left.UserPrincipalName == $right.RiskyUser
| where TimeGenerated > RiskyTime // Activity after the risky sign-in
| where TimeGenerated < datetime_add('hour', 2, RiskyTime) // Within 2 hours
| summarize
PostRiskApps = make_set(AppDisplayName, 10),
PostRiskIPs = make_set(IPAddress, 5),
EventCount = count()
by UserPrincipalName
// Review: What applications did the user access after the risky sign-in?
// Were the non-interactive events from the same IP as the risky sign-in or a different one?
// Different IP = potential token theft in progressReal-time vs offline: why the timing matters
The distinction between real-time and offline detections has a direct impact on your security posture.
Real-time detections are available during the authentication process. A conditional access policy that requires MFA for medium or higher sign-in risk can respond to a real-time detection immediately — the user is challenged for additional verification before access is granted. If the attacker cannot complete the additional challenge, the attack is blocked at the moment of initial access.
Try it yourself
Try It — Explore Your Risk Signals
Environment: Your M365 developer tenant with Sentinel workspace.
Exercise: Run the risk detection overview query from above. In a new developer tenant with limited activity, you may see zero risk detections — this is normal because Identity Protection needs a baseline of sign-in behavior before it can identify anomalies.
To generate risk signals for testing: sign in from a different network (mobile hotspot, VPN to a different country). Wait 15-30 minutes and check the sign-in logs for risk fields. You may see "unfamiliarFeatures" in the RiskEventTypes_V2 field.
Then check the Risky Users blade in the portal: Entra admin center → Identity → Protect & secure → Identity Protection → Risky users. Note the users, their risk levels, and the risk detail. Compare what you see in the portal with what the KQL query returns. The portal and the KQL query should show the same data — but the KQL query is faster at scale.
The myth: We enabled Identity Protection. It uses AI to detect identity attacks. We are protected.
The reality: Identity Protection is a detection engine, not an enforcement engine. By itself, it detects risk and flags accounts — but it does not take action unless you configure risk policies in conditional access (EI5). A tenant with Identity Protection enabled but no risk-based conditional access policies will see risk detections in the logs and the portal, but no sign-in will be blocked and no user will be prompted for remediation. The detections are data without enforcement. Additionally, Identity Protection's detections have blind spots — a well-crafted AiTM attack from the same country as the user, using a VPN exit node with a clean reputation, may not trigger any risk detection. Custom detection rules in Sentinel (EI13) complement Identity Protection by catching patterns that the built-in model misses.
Entra ID Identity Protection flags a sign-in as 'High Risk' due to unfamiliar sign-in properties. The user is a new employee who started this week and is signing in from their home for the first time. Do you block the sign-in?
Not automatically. New employees generate Identity Protection alerts because they have no established baseline — every sign-in property is 'unfamiliar' for a user with no history. The response: (1) verify the sign-in is from the new employee (check with HR or the hiring manager), (2) dismiss the risk detection as a confirmed false positive (this trains Identity Protection's machine learning), (3) document the pattern so future new employee onboarding includes a note to the SOC: 'New employee [name] starting [date] — expect Identity Protection alerts for the first 2 weeks.' The alternative — blocking new employees on day 1 — creates a terrible onboarding experience and a flood of helpdesk tickets.
You've mapped the identity threat landscape and learned to read sign-in logs.
EI0 established that every cloud attack starts with identity. EI1 took you through the signal that matters most — interactive, non-interactive, service principal, and managed identity sign-ins. Now you engineer the defences.
- 17 engineering modules — authentication methods, conditional access architecture, Identity Protection, PIM, token protection, application governance, and detection rules
- The Defense Design Method — the six-step framework applied to every identity control you'll build
- EI18 Capstone — Identity Security Architecture Design — design complete identity architectures for three realistic organisations (SMB, mid-market, regulated enterprise)
- Identity Security Toolkit lab pack — deployable conditional access policies, PIM configurations, and Identity Protection risk rules
- Cross-domain detection (EI16) — email-to-identity correlation and the full phishing-to-inbox-rule attack chain