Entry Point: Identity Posture Assessment
Tools
- CISA ScubaGear — M365 / Entra baseline audit (deterministic, automated)
- Microsoft Secure Score — built-in identity dashboard at
security.microsoft.com - Cazadora — OAuth application enumeration
- Entra sign-in logs export (90d) — baseline auth-protocol distribution
Immediate Posture Check
# Is device-code flow allowed for all users? (the device-code phishing primary control)
Get-MgIdentityConditionalAccessPolicy | Where-Object {
$_.Conditions.AuthenticationFlows -ne $null
} | Select-Object DisplayName, State
# How many users have FIDO2 / Windows Hello enrolled?
Get-MgReportAuthenticationMethodUserRegistrationDetail -All |
Group-Object MethodsRegistered | Select-Object Count, Name
# How many service principal secrets are older than 12 months?
Get-MgServicePrincipal -All | ForEach-Object {
Get-MgServicePrincipalPasswordCredential -ServicePrincipalId $_.Id |
Where-Object { $_.StartDateTime -lt (Get-Date).AddMonths(-12) }
}
If device-code flow is unrestricted, <50% FIDO2 enrollment, or any SP secret >12mo — these are the first three priorities.
Output
One-page identity-posture scorecard (red/amber/green per loop) + prioritized remediation roadmap. Includes a remediation cost ladder (free config → €13/user FIDO2 → €5.50/user Entra P1 → €9/user Entra P2) so the buyer can choose where to stop.
The Identity Attack Surface — Six Branches
1. Credential phishing / spraying / reuse
Attacker has password but no second factor. Closed by MFA on every account, no exceptions, no legacy auth.
2. Adversary-in-the-Middle (AiTM) proxy phishing
Evilginx-style reverse proxy harvests credential AND session cookie mid-auth. User completes MFA legitimately; attacker walks away with cookie. Closed by origin-binding (FIDO2) which the proxy cannot replicate.
3. Device-code phishing
Attacker initiates OAuth Device Authorization Grant flow, tricks user into entering code at the real microsoft.com/devicelogin. No fake page; user's existing session satisfies the IdP; tokens issued to attacker. Closed by restricting the grant flow at the Conditional Access layer.
4. OAuth consent abuse
Attacker convinces user (or admin) to consent to a third-party app requesting broad scopes (Mail.Read, Files.ReadWrite.All, offline_access). App retains access independent of credentials — password reset is irrelevant. Closed by restricting user consent to verified publishers + admin-approval workflow for sensitive scopes.
5. Token theft / refresh-token persistence
Attacker steals access or refresh token from an authenticated endpoint (cookie file, malware exfil, infostealer log). Stolen refresh token mints new access tokens for up to 90 days — survives password reset. Closed only by device trust (replay from unmanaged device blocked) or by aggressive sign-in frequency policies.
6. Non-Human Identity (NHI) compromise
API keys, service principal secrets, OAuth client secrets, CI/CD tokens, package registry tokens, AI platform keys — identities without MFA, often with broad scopes, rarely rotated, often unowned. Compromise via infostealer log, paste site, public repo, or insider. Closed only by inventory + named ownership + rotation discipline + least-privilege scoping.
Conditional Access Evolution Path
| # | Step | Closes branches | Cost | Effort |
|---|---|---|---|---|
| 1 | Block device-code flow by default, allow only by app + IP exception. Runbook → | Branch 3 | Free (config) | 15 min + 1 wk Report-only review |
| 2 | Block user OAuth consent; admin-only approval for risky scopes | Branch 4 | Free (config) | 30 min + admin workflow setup |
| 3 | Shorten access + refresh-token lifetimes; sign-in frequency controls for sensitive apps | Branch 5 (token persistence) | Free (Entra P1) | 1 hr per sensitive-app group |
| 4 | CA uses risk + behavior + device compliance, not just success/failure — risk-based grants, named locations, compliance grants | Branches 2, 5; raises cost of all branches | Entra P2 (~€9/user/mo for risk signals) | 2–5 days policy design |
| 5 | Phishing-resistant MFA (FIDO2 / passkeys) for privileged roles; then expand to workforce | Branches 1, 2 architecturally | €13.50–28/user one-time (keys); free for Windows Hello | 2–4 weeks rollout |
Continuous Authentication — Closing the Token Validity Window
What it actually is
In M365 / Entra terms, continuous authentication = CAE: a session-aware token-revocation mechanism that re-evaluates active sessions against risk signals continuously, rather than trusting the access token until natural expiry. Free, included in Entra P1 (and therefore in M365 Business Premium), off by default in many tenants.
Behavioral continuous auth — keystroke cadence, mouse movement, gait analysis (BehavioSec, TypingDNA, et al.) — is a separate concept that detects "someone else is at the keyboard" after MFA succeeded. Real research field, narrow enterprise adoption, high false-positive rates, expensive add-on. Useful in specific high-value scenarios (admin consoles, financial trading desks); not a general identity-hardening lever.
Risk signals that trigger CAE re-evaluation
- User risk change — Entra ID Protection flags leaked credential, anonymous IP, atypical sign-in
- Account disabled or deleted
- Password reset (forced re-auth)
- MFA registration changes
- Group or role membership changes (privilege gain/loss)
- Device compliance state change (Intune marks device non-compliant)
- Conditional Access policy changes affecting the session
- Sign-in location change outside named trusted locations (with "Strictly enforce location policies" enabled)
Where continuous auth actually prevents identity theft
- Branch 5 (token theft mid-session): the stolen cookie or refresh token becomes useless within ~1 minute of a risk event — instead of working for ~1 hour (access token) or up to 90 days (refresh token). The single biggest CAE win.
- IR containment latency:
Revoke-MgUserSignInSession+ CAE = near-instant eviction; without CAE you wait an hour for the next token refresh. Cuts mean-time-to-evict from hours to minutes. - Reactive credential exposure: when a feed (HIBP, SpyCloud, Entra ID Protection) flags a leaked credential while a session is live, CAE forces immediate re-auth instead of waiting.
- Compliance drift: laptop loses Intune compliance during a session → access cut, not waited out.
Where continuous auth doesn't help — be honest about this
- Branch 3 (device-code phishing): the auth was satisfied legitimately by the victim's existing session. No risk signal fires. CAE catches nothing. Mitigation is at the grant-flow restriction layer, not the session-revocation layer.
- Branch 4 (OAuth consent abuse): the rogue app's token was issued via legitimate consent. CAE doesn't re-evaluate OAuth grants on user risk in any useful way.
- Branch 6 (NHI compromise): service principals aren't user sessions in the CAE sense. No re-auth to force.
- Token exfiltrated to attacker hardware without risk signal: CAE only triggers on signals. If your detection pipeline doesn't generate one, the stolen token works until natural expiry.
The four-layer token-theft architecture
Continuous auth is one layer of four. Each closes a different attack mode; none replaces the others. The complete defense for token theft requires all four:
| Layer | What it closes | Latency | Cost |
|---|---|---|---|
| FIDO2 / passkey origin binding | Proxy AiTM — credential never leaves correct origin, no cookie to steal | Architectural — n/a | €13.50–28/user one-time |
| Continuous Access Evaluation | Token theft after risk signal fires — shrinks revoke window | ~1 min (vs ~1h default) | Free (Entra P1) |
| Device trust via Conditional Access | Token replay from unmanaged endpoint — blocks attacker's device entirely | Per-request | Free (Entra P1) |
| Short refresh-token lifetime | Long-lived refresh tokens that bypass risk signals — forces re-auth on cadence | 1–7 days vs 90d default | Free (Entra P1) |
Implementation actions
- Enable CAE: Entra → Conditional Access → new policy → Session controls → Customize Continuous Access Evaluation → Strictly enforce location policies (or "Disable" if you need to temporarily roll back)
- Verify CAE-aware applications: Exchange Online, SharePoint, Teams, Graph are CAE-enabled by default. Third-party apps need explicit CAE support — check vendor docs before assuming coverage
- Enable Entra ID Protection — risky-sign-in and risky-user signals are the highest-value CAE triggers
- Wire Intune device compliance as a CAE trigger — non-compliance → session terminated within ~1 min
- Pair CAE with sign-in frequency policy — CAE alone doesn't shorten the worst case (a token surviving 90 days because no risk signal ever fires); aggressive sign-in frequency caps the worst case directly
- Validate CAE: revoke a test account's sessions, confirm token invalidation in another browser within ~1 min (not 1 hour). If it takes an hour, CAE isn't actually on for that app
Revoke-MgUserSignInSession should not be against a real compromised account.- Document who can revoke refresh tokens right now — if nobody knows, that's finding #1
- Test
Revoke-MgUserSignInSessionagainst a known test account — build the muscle memory - Create
#identity-incidentschannel — separate from generic security channel; lower noise - Enable Continuous Access Evaluation (CAE) — revokes tokens within ~1 min of risk change instead of default 1h
- Pre-stage O365 Investigation Tooling scripts —
RemediateBreachedAccount.ps1,DumpDelegatesandForwardingRules.ps1 - Plant Canarytokens identity tripwires — fake Azure credentials in SharePoint; tripped on attacker recon
- Identity-IR action cards (max 2 pages each): account takeover, device-code phishing, OAuth consent abuse, NHI compromise, privileged account compromise — all linked from Identity Breach Response playbook
- Pre-built Microsoft Graph scripts tested against client tenant: bulk session revoke, OAuth grant audit, device de-registration, MFA method reset
- Named owner per response action: who revokes, who communicates, who escalates, who signs off — with backups
- 2-hour tabletop: "The CFO's session token has been stolen — walk through containment, scope, and communication"
Compromise indicator → sessions revoked → credentials rotated → persistence removed → blast radius reported — within 15 minutes, by muscle memory, not improvisation. See Identity Breach Response for the live runtime.
- Alert on
authenticationProtocol = "deviceCode"in Entra sign-in logs — the device-code phishing signature (Storm-2372, EvilTokens, Tycoon 2FA, FlowerStorm). Ready-to-paste KQL for 8 alert variants → - Alert on new device registration events — Primary Refresh Token (PRT) persistence vector
- Alert on OAuth admin-consent-grant events (audit log
Add app role assignment grant to user) - Alert on inbox-rule creation, especially rules that move/delete/forward mail
- Enable Entra ID Protection risky-sign-in detection (Security Defaults or Conditional Access)
- Deploy Check by CyberDrain — AiTM proxy detection extension covering the proxy branch (which deviceCode alerts won't catch)
- Subscribe to HIBP domain monitoring — exposed credentials for your domain, free for tenant owners
- Post-token correlation rule: single token session producing bulk Microsoft Graph mail reads + new inbox rule + OneDrive enumeration → high-confidence post-compromise signature
- Impossible-travel + atypical-location tuned against business-travel + VPN/mobile false positives using Entra ID risk + behavioral baseline
- NHI anomaly detection: long-lived API key going silent or appearing from a new ASN — treat the silence as a signal
- Exposure-driven monitoring: infostealer log / combolist feeds (SpyCloud, HIBP, vendor breach notifications) cross-referenced against tenant identities; act before the credential is used. Apply combolist provenance gating (51% overlap rule) to suppress recycled-credential noise
- AiTM honeytoken deployment (zolder.io pattern) — tripwire for the proxy branch
- Detection validation: controlled device-code phishing simulation + AiTM proxy simulation through the pipeline
Every branch of the identity attack tree produces a dedicated alert within minutes of the first attacker action. Exposure-driven monitoring catches compromise before the credential is used, reducing how often full IR is triggered. Combolist provenance gating prevents megabreach-driven false alarms.
- Restrict OAuth 2.0 Device Authorization Grant flow via Conditional Access — block entirely for privileged roles and accounts with no keyboardless-device use case. Closes the device-code phishing primary vector. Config-only. Step-by-step policy build →
- Reduce refresh-token lifetime via sign-in frequency policy for sensitive mailbox apps — default 90 days is the persistence problem; cut to 1–7 days for high-risk apps
- Block legacy authentication protocols (IMAP/POP3/SMTP basic auth) — 99% of password-spray attacks use these
- Restrict OAuth user consent — require admin consent for any app requesting
Mail.Read,Mail.Send,Files.ReadWrite.All,Directory.Read.All,offline_access - Restrict OAuth consent to verified publishers only — blocks the most common malicious-app pattern
- Enable Continuous Access Evaluation — revokes tokens on risk-state change in ~1 min vs default 1h
- Force password manager adoption with origin-binding (autofill only on correct domain) — free phishing-resistant credential layer
- Push Windows Hello for Business to all managed devices — device-bound passkey, zero hardware cost
- FIDO2/passkey rollout (~€13.50–28/user one-time) — origin binding makes AiTM proxy phishing architecturally impossible. Phased: finance + executives + admins first, then general workforce
- Device trust via Conditional Access (Entra P1, included in Business Premium) — the ONLY control that closes token theft at rest. Stolen session cookie replayed from unmanaged device is blocked
- Conditional Access policy set: risk-based (impossible travel, anonymous IP, leaked credentials), device-compliance, named-location, app-restriction, admin-protection
- Entra Privileged Identity Management (PIM) (Entra P2 ~€9/user/mo) — just-in-time admin role activation; no standing admin access. Targets admin accounts only, not full workforce
- Block device code flow universally except for explicitly listed apps via CA policy template
- Microsoft Authenticator number-matching + additional context — closes MFA fatigue/bombing class without hardware key rollout
All authentication phishing-resistant (FIDO2 / Windows Hello). All access from compliant devices. Refresh tokens scoped to minimum viable lifetime for sensitive apps. Device-code flow blocked except where justified. OAuth user-consent locked down. AiTM proxy attacks architecturally impossible. Token theft at rest blocked by device trust.
- Export MFA exception list — most exceptions are years old, no longer needed
- Audit OAuth consent grants tenant-wide:
Get-MgServicePrincipal -All | Get-MgServicePrincipalOauth2PermissionGrant | Where-Object {$_.ConsentType -eq "AllPrincipals"} - Review dormant accounts (90+ days no sign-in) — disable or delete
- Review device registrations — unused devices are PRT-persistence opportunities
- Review risky users + risky sign-ins last 30 days — close out resolved, investigate open
- NHI starter inventory — list service principals with secrets/certs older than 12 months; assign owners
- Schedule monthly ScubaGear re-scan against Entra baseline to catch drift
- Identity drift detection: monthly automated checks (MFA exceptions, missing FIDO2 enrollments, new OAuth consents, stale service principals, dormant accounts, sign-in risk trends)
- Onboarding/offboarding identity integration: FIDO2 enrollment as day-1 step, refresh-token revocation as last-day step, device de-registration on departure
- NHI rotation policy: service principal secrets ≤ 12 months, API keys ≤ 6 months, named owner per token, registry of usage. Covers human-adjacent NHIs (CI/CD, IaC tokens) AND AI platform keys (OpenAI, Anthropic) AND package registry tokens (PyPI, NPM) AND developer platform tokens (GitHub, Atlassian)
- Quarterly access reviews via Entra ID Governance (P2) — automated review of group/role membership and guest access
- Identity Posture Score tracked over time — not just a snapshot. Show drift in board reporting
No silent decay. Every employee FIDO2-enrolled. Every departure revoked. Every NHI inventoried, owned, rotated. Every MFA exception reviewed quarterly. Drift caught within one cycle, not one breach.
- Write the identity-program charter: who owns identity strategy, how decisions are made, who can grant exceptions. One page, signed by CISO.
- Add FIDO2 enrollment to onboarding checklist — spreadsheet-tracked is fine to start
- Subscribe to exposure intelligence feeds for your domain (HIBP, vendor breach notifications) — act on identity exposure before incident
- Universal FIDO2 / passkey enrollment — origin binding closes the proxy-AiTM branch entirely; no password remains to phish. Phased rollout, executive sponsorship, hardware key procurement, fallback handling
- Device trust as universal precondition for sensitive data access — stolen tokens worthless from unmanaged endpoints. Conditional Access policy set, Intune compliance baseline, BYOD policy
- Non-Human Identity program: inventory + ownership + rotation policy + least-privilege scoping. Treat NHIs as a distinct identity class, not a sub-case. Cover: AI platform keys (OpenAI, Anthropic), developer platform tokens (GitHub, Atlassian, GitLab), CI/CD secrets, package registry tokens (PyPI, NPM), Slack/Teams API tokens, cloud-platform service principals. The 5x YoY growth in third-party app credentials makes this the under-served consulting category
- Exposure-driven response architecture: continuous dark-web monitoring (SpyCloud or equivalent) feeds proactive remediation. Stated value: act on exposure data before a confirmed incident, reducing IR trigger frequency
- Privileged Identity Management at scale: PIM for all admin roles (eligible, not active); approval workflow for sensitive activations; quarterly access reviews; tier-0/1/2 admin model
- NIS2 Article 21 alignment: map identity controls to access control, incident handling, supply chain (third-party identity exposure), management accountability. Provides demonstrable compliance evidence for regulators
- Board reporting template: quarterly identity-posture report — FIDO2 coverage %, NHI rotation status, MFA bypass attempt rate, mean-time-to-revoke, exposed-credential count
Identity exposure is treated as a measurable, manageable attack surface — not a series of isolated incidents. Stolen credentials don't work (FIDO2 phishing-resistant). Stolen tokens don't work (device trust). Stolen NHI keys are detected (anomaly + rotation discipline). Mean time from exposure to revocation is shorter than mean time from exposure to weaponization.
Program Economics (200-seat reference)
| Engagement | Duration | Investment |
|---|---|---|
| Assessment + quick wins handoff | 1–2 days | €1,250 – 2,500 |
| 1 Containment (pre-staged scripts, tabletop, action cards) | 1 day | €1,250 |
| 2 Detection (six-branch alerting + exposure intel) | 2–3 days | €2,500 – 3,750 |
| 3 Posture (CA, FIDO2, device trust, token lifetimes, PIM) | 2–3 days | €2,500 – 3,750 |
| 4 Vulnerability Management (drift, NHI inventory, reviews) | 1 day + quarterly | €1,250 + €5,000/yr |
| 5 Structural (FIDO2 rollout, NHI program, exposure intel) | 3–5 days | €3,750 – 6,250 |
| Full program | 10–15 days | €12,500 – 18,750 + retainer |
Identity Hardening: Free Afternoon Deploy
| # | Action | Time | Tool |
|---|---|---|---|
| 1 | Run ScubaGear baseline assessment | 1 hour | ScubaGear |
| 2 | Restrict OAuth Device Authorization Grant flow | 15 min | Entra Conditional Access |
| 3 | Enable Continuous Access Evaluation (CAE) | 15 min | Entra CA policy |
| 4 | Reduce refresh-token lifetime for high-risk apps | 30 min | Entra sign-in frequency |
| 5 | Block legacy authentication protocols | 15 min | Entra Conditional Access |
| 6 | Restrict OAuth user consent (high-privilege scopes) | 15 min | Entra Enterprise Apps |
| 7 | Restrict consent to verified publishers | 10 min | Entra app consent policy |
| 8 | Enable Microsoft Authenticator number-matching | 15 min | Entra auth methods |
| 9 | Alert on authenticationProtocol = deviceCode | 15 min | Sentinel / sign-in logs |
| 10 | Alert on new device registration + OAuth consent | 20 min | Entra audit logs |
| 11 | Push Windows Hello for Business | 1 hour | Intune / Group Policy |
| 12 | NHI starter inventory: service principals with stale secrets | 1 hour | Graph PowerShell |
| 13 | Plant identity canarytokens in SharePoint | 30 min | Canarytokens |
Free / Open-Source Tools
- CISA ScubaGear — M365 / Entra baseline audit
- Cazadora — OAuth app hunting in M365
- Check by CyberDrain — AiTM proxy detection extension
- Canarytokens — Free identity tripwires
- O365 Investigation Tooling — IR scripts pre-staged
- HIBP — Domain monitoring (free for tenant owners)
- zolder.io AITMWorker + honeytokens — AiTM detection PoC + defender guide
- Microsoft Graph PowerShell SDK — baseline + remediation scripting
Key Configuration Commands
# FIDO2 enrollment status across tenant
Get-MgReportAuthenticationMethodUserRegistrationDetail -All |
Group-Object MethodsRegistered | Select Count, Name
# Find OAuth grants to AllPrincipals (tenant-wide consents)
Get-MgServicePrincipal -All |
Get-MgServicePrincipalOauth2PermissionGrant |
Where-Object { $_.ConsentType -eq "AllPrincipals" }
# Find service principal secrets > 12 months old
Get-MgServicePrincipal -All | ForEach-Object {
Get-MgServicePrincipalPasswordCredential `
-ServicePrincipalId $_.Id |
Where-Object {
$_.StartDateTime -lt (Get-Date).AddMonths(-12)
}
}
# Sign-in logs filtered to device-code flow (hunt)
Get-MgAuditLogSignIn `
-Filter "authenticationProtocol eq 'deviceCode'" `
-Top 100 | Select-Object CreatedDateTime, UserPrincipalName, `
IpAddress, AppDisplayName, Status
# List all enabled Conditional Access policies
Get-MgIdentityConditionalAccessPolicy |
Where-Object { $_.State -eq "enabled" } |
Select DisplayName, State, CreatedDateTime
Companion Playbooks
Identity Hardening is the canonical home for FIDO2, Conditional Access, token discipline, OAuth consent posture, and NHI program design. These adjacent playbooks cover identity from different vector entry points:
Identity Breach Response
Active IR for credential, session, token, OAuth, or NHI compromise. T+0–15 min containment, 8 incident-type variations.
BEC Defense
Identity hardening through the email lens: impersonation rules, finance OOB verification, mailbox forwarding lockdown.
Supply Chain Security
Vendor identity exposure, MSP access controls, B2B guest access, OAuth consent for third-party SaaS.
Cloud Security
Cloud-platform IAM, managed identities, IP-bound API keys, public-access prevention across the Big 3 clouds.