Identity Risk Alert to Teams
When an Azure AD risk event is detected, post an alert to a security Teams channel with user details and recommended actions.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
FlowLibs - Identity Risk Alert to Teams is a scheduled cloud flow that polls Microsoft Entra Identity Protection for users currently in an "atRisk" state and posts an alert to a designated security Teams channel for every match that meets a configurable risk-level threshold. Each alert contains the user's display name, UPN, risk level, risk state, risk detail, last-updated timestamp, and a checklist of recommended remediation steps so the security team can triage immediately from inside Teams.
Use Case
Identity Protection surfaces sign-in and user-risk signals (atypical travel, anonymous IP, leaked credentials, anomalous activity, etc.), but those signals only deliver value if a human sees them and acts. This flow eliminates the "nobody checked the Entra portal today" gap — instead of relying on the security team to log into Entra, it pushes high-signal risk events into the channel they already live in. Every detection that crosses the configured severity floor becomes a Teams card with the exact context an analyst needs to confirm or dismiss the risk, reset the password, and revoke sessions.
This is a defense-in-depth pattern that complements (does not replace) Conditional Access. CA blocks risky sign-ins automatically; this flow ensures someone follows up on the user behind the block.
Flow Architecture
Check For Risky Users On Schedule
Recurrence (1 hour)Polls on a fixed cadence — change frequency/interval to match the security team's SLA.
Init varGraphApiEndpoint
Initialize VariableLoads `flowlibs_GraphApiEndpoint` env var into a runtime variable.
Init varRiskLevelMinimum
Initialize VariableLoads `flowlibs_RiskLevelMinimum` env var (low / medium / high).
Init varTeamsGroupId
Initialize VariableLoads `flowlibs_TeamsGroupId` env var.
Init varTeamsChannelId
Initialize VariableLoads `flowlibs_TeamsChannelId` env var.
Compose Allowed Risk Levels
ComposeExpands the minimum into an array (e.g. medium → ["medium","high"]) so the loop can do an O(1) inclusion check.
Get Risky Users From Graph
HTTP (built-in, ActiveDirectoryOAuth)`GET {endpoint}/identityProtection/riskyUsers?$filter=riskState eq 'atRisk'&$top=50&$orderby=riskLastUpdatedDateTime desc`
Parse Risky Users Response
Parse JSONStrongly-types the Graph response so downstream actions get tokenized fields.
For Each Risky User
Apply to eachIterates the `value` array from the Graph response. For each user, evaluates whether the risk level meets the configured threshold and posts an alert when it does.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_GraphApiEndpoint | String | https://graph.microsoft.com/v1.0 | Base URL for Graph; switch to a beta endpoint or sovereign cloud if needed. |
| flowlibs_RiskLevelMinimum | String | medium | Severity floor — one of `low`, `medium`, `high`. Anything below is filtered out in the loop's condition step. |
| flowlibs_RiskCheckIntervalHours | String | 1 | Documentation of intended polling cadence. The Recurrence trigger has interval `1` hardcoded — update both together when changing. |
| flowlibs_TeamsGroupId | String | <configure> | Object ID of the Microsoft 365 Group that owns the security Teams channel. |
| flowlibs_TeamsChannelId | String | <configure> | Channel ID of the security alerts channel in that team. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Microsoft Teams | shared_teams | PostMessageToConversation (posts alert HTML to security channel) |
| HTTP (built-in) | n/a | HTTP (Calls Graph /identityProtection/riskyUsers with ActiveDirectoryOAuth (App Registration credentials)) |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Adjusting cadence
- Change the Recurrence trigger's frequency and interval to match your team's tolerance for delay. For SOC environments, every 15 minutes (frequency: Minute, interval: 15) is more typical. Update flowlibs_RiskCheckIntervalHours in parallel so the env var stays in sync with reality.
- Tuning severity
- Update the flowlibs_RiskLevelMinimum env var value to low, medium, or high. The Compose Allowed Risk Levels expression rebuilds the inclusion array at every run — no flow edits required.
- Targeting a different channel
- Update flowlibs_TeamsGroupId and flowlibs_TeamsChannelId and re-authorize the Teams connection if it points to a different identity. The flow does not need to be edited.
- Switching from app-only to delegated auth
- Replace the HTTP action's ActiveDirectoryOAuth block with a ManagedServiceIdentity block (Azure-hosted scenarios) or migrate to the HTTP with Microsoft Entra ID (preauthorized) connector. The downstream Parse JSON / For Each / Teams steps stay unchanged.
- Enriching the Teams card
- Replace the HTML in body/messageBody with an Adaptive Card payload to add Approve / Dismiss buttons. Wire those buttons to a follow-up Wait for Adaptive Card response action, then call Graph PATCH /identityProtection/riskyUsers/confirmCompromised or dismiss to close the loop without leaving Teams.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Severity floor expansion
Used in Compose Allowed Risk Levels — expands the minimum severity into an inclusion array so the loop's condition is an O(1) contains check.
EXPR.02Inclusion check
Used in the Check If Risk Level Meets Threshold condition; lower-cases the item's risk level for case-insensitive matching.
EXPR.03Graph URI builder
URI for the Get Risky Users From Graph HTTP action — concatenates the env-var endpoint with the riskyUsers path.
EXPR.04Teams card body field lookups
Every dynamic value in the Teams alert message is a slash-path lookup off the foreach iterator.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.