Security Identity

Rolling Out Phishing-Resistant Passwordless Auth: FIDO2, Passkeys, and Break-Glass Design

At 09:41 an employee gets an email that looks exactly like a Microsoft sign-in prompt, clicks it, and lands on a page that is pixel-perfect — because it is the real page, proxied. She types her password, approves the Microsoft Authenticator push, even matches the two-digit number. Everything succeeds. And an attacker three time zones away now holds her session cookie and is reading her mailbox, because the whole exchange ran through an adversary-in-the-middle (AiTM) proxy that relayed every factor in real time. Nothing she did was wrong. The problem is that every factor she used — password, push, OTP — is something a human can be induced to transcribe or approve into the wrong place, and a live relay defeats all of them. Number matching slowed bulk MFA-fatigue spam; it does nothing against a proxy that forwards the number for the user.

The only credential that survives this is one that is cryptographically bound to the origin it was registered for and whose private key never leaves the authenticator. That is precisely what FIDO2 (WebAuthn on the browser side, CTAP2 on the authenticator side) and passkeys give you. A credential registered for login.microsoftonline.com will not, cannot, produce a valid assertion for login.microsoftonIine.com or any proxy — the browser refuses to even attempt it, because the origin in the request doesn’t match the origin bound into the key. There is no shared secret to phish, no code to relay, no push to fat-finger. This article is the production deployment runbook for getting an entire organization there on Microsoft Entra ID without the two catastrophic failure modes on either side of the path: leaving the AiTM hole open because you never enforced, or locking every administrator out of the tenant because you enforced before break-glass was real.

We treat this as a sequenced migration, not a feature toggle. You will learn the WebAuthn/CTAP2 mechanics well enough to explain why the phishing resistance holds and where it can still be bypassed; the real differences between device-bound and synced passkeys and when each is acceptable; how security keys, platform authenticators (Windows Hello for Business, Face/Touch ID), and Authenticator passkeys differ operationally; how to model the Authentication methods policy, authentication strengths, and Conditional Access so that “this resource requires phishing-resistant” is a policy object and not a hope; how AAGUID allow-lists and attestation actually restrict which hardware may register, and where Microsoft is moving that control surface; how to drive enrollment at scale with Temporary Access Pass (TAP) and registration campaigns; how to design and rehearse break-glass FIDO2 accounts; and how to migrate off legacy MFA and recover a user who lost their only key — with real Graph, PowerShell, az, and KQL throughout, and enough reference tables to keep open during the rollout.

What problem this solves

Most multi-factor authentication in production today is phishable. That is not a slur on MFA — turning it on was the single highest-ROI security move of the last decade and it stopped an enormous volume of password-spray and credential-stuffing. But the attacker economics moved. AiTM phishing kits (Evilginx, EvilProxy, and their commercial subscription descendants) are cheap, templated, and specifically engineered to sit between the user and the real identity provider, relaying the password, the OTP, and the push approval, then stealing the post-authentication session token. Once they hold that cookie, MFA is behind them; it already succeeded. Token theft and AiTM are now the dominant path into cloud tenants, and they walk straight through SMS codes, TOTP authenticator apps, and push-with-number-matching alike.

What breaks without phishing-resistant auth is subtle because sign-ins keep succeeding. There is no failed-login spike to alert on; the user authenticated, the factor was satisfied, the session issued. The compromise shows up later as mailbox rules that auto-forward and delete, as OAuth consent grants to attacker apps, as lateral movement using the stolen session, as business email compromise wired to a supplier. Teams discover it in incident response, not in the sign-in logs, because from Entra’s perspective at the moment of sign-in nothing was wrong. The gap is architectural: any factor a human can relay is relayable, and the human is always in the loop for password/OTP/push.

Who hits this: everyone with a cloud identity, but the blast radius is worst for privileged identities (a phished Global Administrator is a tenant-level event) and for high-value line-of-business users (finance, executives, anyone who can move money or approve access). It bites hardest in organizations that “have MFA” and therefore believe they are covered — the false sense of completeness is itself the risk. The fix is not more MFA; it is a different class of factor. And the deployment is genuinely hard, not because the crypto is hard, but because you must roll out a new credential to thousands of humans on messy hardware, enforce it without stranding anyone, and build a recovery path that is itself phishing-resistant yet always available. That sequencing — methods on, adoption proven, strength enforced, break-glass rehearsed — is the whole discipline.

To frame the field before the deep dive, here is the landscape of what is and isn’t phishing-resistant, and why:

Factor Phishing-resistant? Why / why not Relayable by AiTM?
Password only No Shared secret; typed into whatever page asks Yes
SMS / voice OTP No Code is transcribed by the human; also SS7/SIM-swap exposed Yes
TOTP authenticator app No 6-digit code typed into the page; proxy forwards it Yes
Push + number matching No User approves/matches into the real IdP via the proxy Yes (live relay)
FIDO2 security key Yes Origin-bound assertion; private key non-exportable, on hardware No
Passkey (device-bound) Yes Origin-bound; key in TPM/Secure Enclave, cannot leave device No
Passkey (synced) Yes (to the origin) Same origin binding; caveat is where the key can sync to No
Windows Hello for Business Yes Origin-bound WebAuthn credential in the device TPM No
Certificate-based auth (CBA, multifactor) Yes PKI cert, often smart-card; strong-auth binding No

The dividing line is exactly one property: does the credential get bound to the origin by the platform, or does a human relay it? Everything in the “Yes” rows is a WebAuthn/CTAP2 or PKI credential where the browser and authenticator enforce origin binding without the human being able to override it.

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should be comfortable in Microsoft Entra ID administration: the difference between the Authentication methods policy and the legacy per-user MFA and Security Defaults surfaces, how Conditional Access grant controls work, what a directory role and its role template ID are, and how to run Microsoft Graph PowerShell (Connect-MgGraph) and az rest against Graph. You should understand managed vs federated authentication (whether sign-in happens in Entra or is redirected to AD FS / a third-party IdP), because federation changes where some of this enforcement lands. Familiarity with TPM 2.0 and hardware-backed key storage helps you reason about platform authenticators.

This sits at the center of the Identity & Zero Trust track and is the credential-layer complement to the policy-layer articles. It assumes the Conditional Access design discipline from Designing Conditional Access at Scale: A Persona-Based Policy Framework with Authentication Context and Filters and the emergency-access hardening from Engineering Break-Glass Emergency Access Accounts in Entra ID: Exclusions, Hardening, and Tamper-Evident Monitoring — this article deepens the FIDO2-specific break-glass angle. It pairs with Privileged Identity Management and PAM Architecture: Just-in-Time Access at Scale (because your most sensitive scope is privileged roles) and with Operationalizing Entra ID Protection: Risk-Based Conditional Access, Detection Tuning, and Risk Investigation (risk signals still matter even when the factor is phishing-resistant). There is a device-management-flavored FIDO2 rollout in Rolling Out FIDO2 Passwordless Authentication in Entra ID: Security Keys, Passkeys, and Windows Hello for Business; this piece is the security-team runbook with the break-glass and migration emphasis.

Here is who owns which layer during the rollout, so you route decisions to the right team:

Layer What lives here Who usually owns it Failure it can cause
Authenticator (key / TPM / Secure Enclave) Private key, user verification, attestation Endpoint / EUC + user Lost key → lockout if no recovery
Browser / platform (WebAuthn client) Origin check, ceremony, clientDataJSON Microsoft / OS vendor Old browser lacks WebAuthn → can’t register
Entra Authentication methods policy Which methods are enabled, scoped, restricted Identity team Method not enabled → users can’t enroll
Authentication strength + Conditional Access “Requires phishing-resistant” enforcement Identity / security Mis-scoped policy → lockout or open hole
Break-glass accounts The way back in Security + IAM leads Not excluded/rehearsed → tenant lockout
Legacy authentication surface POP/IMAP/SMTP/older EAS Messaging + identity Left open → bypasses everything above

Core concepts

Six mental models make every later decision obvious.

The status of “phishing-resistant” is a property of origin binding, not of hardware alone. FIDO2 resistance comes from the browser refusing to run a WebAuthn ceremony for the wrong origin, and from the authenticator signing over data that includes the relying party. A hardware key used badly (e.g., a poorly implemented protocol) could in principle be weaker; a synced passkey used well is still origin-bound. So “phishing-resistant” is earned by the WebAuthn/CTAP2 flow, and the hardware question (device-bound vs synced) is about key location and portability, which is a different axis. Conflating the two is the most common conceptual error.

The credential is a key pair the authenticator holds; the server only ever sees a public key. At registration, the authenticator generates a new key pair unique to that relying party and returns the public key plus metadata; the private key stays in the authenticator (security key, TPM, or Secure Enclave) and, for device-bound credentials, is non-exportable — there is no API to read it out. At sign-in, the server sends a random challenge, the authenticator signs it with the private key (after verifying the user), and the server verifies the signature against the stored public key. Nothing secret ever transits the network. Compare that to a password (the secret transits every login) or a TOTP seed (a shared secret both sides know).

The RP ID and origin check is the anti-phishing mechanism. When the browser starts a WebAuthn ceremony, it constructs clientDataJSON containing the origin (https://login.microsoftonline.com) and the challenge, and hashes it. The authenticator signs over the RP-ID hash plus the client-data hash. The relying party (Entra) then verifies both the signature and that the origin in clientDataJSON matches its expected origin. A proxy at login.microsoftonIine.com produces a different origin, so the browser will not use a credential registered for the real domain, and even if it somehow produced an assertion, Entra would reject the origin mismatch. There is no step where a human can “approve anyway” past a wrong origin — that is the whole point, and it’s why phishing resistance is a platform-enforced property, not a user-judgment one.

User presence and user verification are two different flags. Every FIDO2 assertion carries flags: UP (user presence) means “a human touched the authenticator” (the tap on a key); UV (user verification) means “the human was verified” — via PIN, biometric, or device unlock. Passwordless sign-in requires UV (the key/PIN or biometric is the second factor, making the single ceremony multi-factor). A bare security-key tap with no PIN gives UP but not UV — fine for a second factor next to a password, not sufficient as a standalone passwordless credential. When you enable FIDO2 passwordless, you are requiring UV.

Device-bound and synced passkeys differ in where the private key can live, not in origin binding. A device-bound passkey (a FIDO2 security key, or a platform credential like Windows Hello for Business) has key material that cannot leave the device; if the device dies, that credential is gone and you re-register. A synced passkey (Apple iCloud Keychain, Google Password Manager, a third-party passkey provider) copies the private key, end-to-end encrypted, across the user’s devices in that ecosystem, so losing one device doesn’t lose the credential. Both are origin-bound and both are phishing-resistant to the relying party. The enterprise concern with synced passkeys is where the key can end up (a personal Apple ID, sharable with family) and whether attestation can even be meaningful (synced credentials often present no attestation or a provider-generic one). This is why attestation and AAGUID allow-lists (below) apply cleanly to device-bound keys and imperfectly to synced ones.

Enforcement is a policy object, not a wish. “This resource requires phishing-resistant MFA” is expressed as an authentication strength — a named object listing the specific method combinations that satisfy it — bound to a Conditional Access policy as a grant control. Enabling FIDO2 in the methods policy only makes it possible to register and use; the strength bound to CA is what makes it required. These are separate layers on purpose: you enable broadly, enforce narrowly, and expand the enforcement ring over time.

The vocabulary in one table

Pin down every moving part before the deep sections. The glossary repeats these for lookup; this is the side-by-side mental model.

Concept One-line definition Where it lives Why it matters here
WebAuthn Browser/JS API for public-key credentials Browser + relying party The origin check that defeats phishing
CTAP2 Protocol between client and authenticator OS ↔ security key/TPM How the key does UV and signs
FIDO2 WebAuthn + CTAP2 together Standard The phishing-resistant credential family
RP ID (relying party ID) The domain a credential is bound to Credential metadata Wrong origin → unusable → no phishing
Passkey A discoverable FIDO2 credential Key / TPM / synced store Umbrella term (device-bound or synced)
Device-bound passkey Non-exportable key, stays on device Security key / TPM Attestable; lost device → re-register
Synced passkey E2E-encrypted key synced across devices iCloud / Google / provider Survives device loss; weak attestation
AAGUID Model identifier of an authenticator Attestation data Allow-list which hardware may register
Attestation Cryptographic proof of make/model Registration statement Verifies the key is what it claims
UV (user verification) Human was verified (PIN/bio) Assertion flag Required for passwordless (MFA in one step)
UP (user presence) A human was present (tapped) Assertion flag Second-factor level; not full MFA alone
Authentication strength Named set of allowed method combos Entra policy object The “requires phishing-resistant” control
Authentication methods policy Which methods are enabled/scoped Entra policy Enables registration + use
TAP (Temporary Access Pass) Time-limited passcode to bootstrap Auth method Register first passkey without a password
WHfB Windows Hello for Business Device TPM Platform authenticator on Windows

How WebAuthn and CTAP2 make phishing resistance real

The phishing resistance is not marketing; it is a specific sequence of cryptographic checks. Walk the two ceremonies once and the property becomes obvious.

The registration ceremony (making a credential)

When a user enrolls a FIDO2 credential for Entra, the browser calls navigator.credentials.create(). The relying party (Entra) supplies PublicKeyCredentialCreationOptions: a challenge (random bytes), the RP information (id: login.microsoftonline.com, name), the user handle, the acceptable public-key algorithms (pubKeyCredParams, e.g. ES256/-7, RS256/-257), an attestation preference (none/indirect/direct/enterprise), and authenticatorSelection (whether it wants a platform or cross-platform authenticator, whether it requires resident/discoverable credentials, and the user-verification requirement). The authenticator generates a new key pair scoped to that RP, stores the private key, and returns an attestation object containing the public key, the AAGUID, the credential ID, and (if requested) an attestation statement signed by the authenticator’s attestation key. Entra validates the attestation (if enforced) against the FIDO Metadata Service (MDS) and stores the public key and credential ID against the user.

The fields that matter, and why:

Registration field What it is Why it matters Entra behavior
challenge Random server nonce Prevents replay of a captured registration Server-generated, single-use
rp.id The relying party domain Binds the credential to the origin login.microsoftonline.com
pubKeyCredParams Allowed key algorithms Negotiates ES256/RS256 etc. Prefers ES256
authenticatorSelection.userVerification required/preferred/discouraged required → passwordless (UV) required for passwordless
authenticatorSelection.residentKey Discoverable credential? Needed for username-less sign-in Passkeys are discoverable
authenticatorSelection.authenticatorAttachment platform vs cross-platform Hello (platform) vs key (cross-platform) Depends on method
attestation none/direct/enterprise Whether make/model is proven direct when attestation enforced
excludeCredentials Already-registered creds Stops double-registering the same key Populated by Entra

The assertion ceremony (signing in)

At sign-in, the browser calls navigator.credentials.get() with PublicKeyCredentialRequestOptions: a fresh challenge, the RP ID, and optionally allowCredentials (which credential IDs are acceptable — empty for discoverable/passkey username-less flows). The browser builds clientDataJSON = { type: "webauthn.get", challenge, origin, crossOrigin }, where origin is the actual page origin. The authenticator verifies the user (UV: PIN/biometric), then signs over authenticatorData ‖ SHA-256(clientDataJSON). authenticatorData includes the RP-ID hash, the flags (UP, UV, etc.), and a signature counter. Entra receives the assertion, looks up the stored public key by credential ID, and verifies: the signature is valid, the RP-ID hash matches, the UV flag is set (for passwordless), the challenge matches the one it issued, and — critically — the origin in clientDataJSON is one Entra expects.

That origin check is the anti-phishing lock. Here is the exact place each phishing attempt dies:

Attack step What the attacker does Where it fails Which check kills it
Lookalike domain Hosts login.microsoftonIine.com Browser won’t use a cred bound to real RP Browser RP-ID scoping
Proxy the real page Relays HTML from real IdP Origin in clientDataJSON is the proxy’s Origin mismatch at Entra
Replay a captured assertion Reuses a signed assertion Challenge is single-use, already consumed Challenge validation
Downgrade to password/OTP Strips FIDO2, asks for a code Strength policy rejects non-PR methods Authentication strength
Steal the private key Extract from the device Key is non-exportable in hardware Authenticator hardware
Clone the authenticator Duplicate the key Signature counter regression detected Counter check (where supported)

The consequence: an AiTM proxy that happily relays a password and a push simply cannot relay a FIDO2 assertion, because the browser won’t produce one for the proxy’s origin and Entra would reject a mismatched origin anyway. There is no shared secret in the exchange to steal and nothing the human can be tricked into typing into the wrong place.

Where phishing resistance can still be bypassed

Honesty matters: the factor is phishing-resistant, but the system can be undermined. These are the residual holes you must close.

Residual risk How it bypasses the strong factor Mitigation
Token/session theft after auth Steal the issued cookie post-sign-in (infostealer, malware) Token protection / bound sessions, short lifetimes, device compliance
Fallback method still enabled User completes sign-in with SMS/TOTP instead Authentication strength that excludes weak methods
Legacy auth protocols POP/IMAP/SMTP can’t do modern MFA at all Block legacy authentication explicitly
Consent phishing (OAuth) Trick user into granting an app, no creds needed App consent governance, admin consent workflow
Help-desk social engineering Attacker convinces support to issue a TAP/reset Verify identity before TAP; alert on TAP issuance
Synced passkey to attacker-controlled account Passkey syncs to a compromised personal cloud Prefer device-bound for high assurance; restrict
Device compromise (malware on endpoint) Malware rides the authenticated session Endpoint EDR, device compliance in CA

The takeaway: FIDO2 removes the credential-phishing class entirely, which is the largest single class. It does not remove token theft, consent phishing, or endpoint compromise — those need their own controls, and the strong factor is the foundation the rest builds on, not the whole building.

Choosing the credential: keys vs platform vs Authenticator passkeys

Entra recognizes several phishing-resistant methods. They differ in where the key lives, portability, attestability, and operational cost. Choose per persona, not one-size-fits-all.

The three enterprise-grade options, side by side

Property FIDO2 security key (hardware) Platform authenticator (WHfB / Face-Touch ID) Microsoft Authenticator passkey (device-bound)
Where the key lives On the portable key (own secure element) Device TPM / Secure Enclave Phone’s hardware keystore
Portable across devices? Yes (carry the key) No (bound to that device) No (bound to that phone)
Device-bound (non-exportable)? Yes Yes Yes (device-bound passkey)
Attestable / AAGUID allow-listable? Yes (strong) Yes (WHfB AAGUID) Yes
User verification PIN or on-key biometric Windows Hello PIN / biometric Phone biometric / PIN
Best for Admins, shared/kiosk, BYOD unmanaged Knowledge workers on managed PCs Workforce with a managed phone, cross-PC
Cost Per-key procurement (₹2,000–6,000+) Free (device TPM) Free (app)
Lost-credential impact Replace key; re-register Re-enroll on device Re-register on new phone
Cross-platform login (any PC) Yes (plug in the key) No Yes (phone-based, cross-device via CTAP)

Security keys — the portable, high-assurance option

A FIDO2 security key is a small hardware token (USB-A/C, NFC, Lightning) with its own secure element. It is portable — the credential travels with the person, not the device — which makes it the right answer for privileged identities, shared workstations, and BYOD you can’t manage. It is the most attestable option: a good key ships a real attestation certificate chain, so an AAGUID allow-list plus attestation enforcement gives you strong assurance the credential is a specific vetted model with non-exportable key material. The costs are logistics: procurement, distribution, a replacement process for loss, and (for the highest assurance) standardizing on one or two models so your allow-list is tight.

Platform authenticators — Windows Hello for Business and Face/Touch ID

A platform authenticator binds the credential to the device’s hardware: Windows Hello for Business (WHfB) uses the PC’s TPM; Apple/Android platform biometrics use the Secure Enclave/StrongBox. This is the low-friction daily driver for knowledge workers on managed devices — no extra hardware to buy or carry, biometric or PIN unlock, and the credential is device-bound and attestable. The limitation is exactly its strength: it is bound to that device. A user with three devices has three separate registrations; a user whose laptop dies re-enrolls. It does not travel, so it is a poor fit for genuinely shared hardware (see edge cases). WHfB has real interplay with FIDO2 that deserves its own section below.

Microsoft Authenticator passkeys — the phone as a roaming authenticator

Microsoft Authenticator can now hold device-bound passkeys on the user’s phone. This gives you a phishing-resistant credential the user already carries, that can sign them in across PCs via the cross-device CTAP flow (the desktop shows a QR/proximity prompt, the phone approves with biometric). It is attractive when the workforce has a managed phone and you don’t want to buy keys for everyone. It is device-bound (the passkey lives in the phone’s keystore, non-exportable), which is what makes it attestable and distinct from a synced consumer passkey. Enable it under the Authenticator method surface, scoped to a pilot group first. Watch the phone-loss recovery path — a lost phone means re-registering the passkey, so pair it with a fallback (a security key, or TAP-driven re-enrollment).

Certificate-based authentication — when you already run PKI

Certificate-based authentication (CBA), typically smart-card, is phishing-resistant and satisfies the built-in phishing-resistant strength when configured as multifactor. It is the right call for regulated/government shops that already operate a mature PKI with CRL/OCSP revocation plumbing. Standing up a PKI just for auth is a large project with real operational weight (issuance, renewal, revocation, HSMs) — reach for CBA when the PKI already exists, not as a greenfield choice over FIDO2.

The persona-to-method decision table

Map populations to methods before you touch policy:

Persona Primary method Secondary / fallback Rationale
Global/privileged admins FIDO2 security key (hardware) Second FIDO2 key Portable, most attestable; second key is the recovery
Knowledge worker (managed PC) Windows Hello for Business Authenticator passkey / security key Free, low friction; phone/key for other devices
Knowledge worker (multi-device) Authenticator passkey (phone) Security key Roams across PCs; key as backup
Frontline / no assigned PC FIDO2 security key Authenticator passkey (BYOD) Portable; personal phone if BYOD policy allows
Shared clinical / manufacturing floor FIDO2 security key Shared-device sign-in Key travels with the person, not the shared TPM
Developers / engineers WHfB + security key Authenticator passkey Hello daily; key for privileged/CLI paths
Executives (target of BEC) FIDO2 security key + WHfB Second key Highest assurance; belt and suspenders
Regulated (existing PKI) CBA (smart card) FIDO2 security key Reuse PKI; key as modern alternative
BYOD, unmanaged FIDO2 security key Authenticator passkey Portable; no device management dependency

A pragmatic default for most enterprises: platform authenticators (WHfB) + Authenticator passkeys as the workforce daily driver, hardware security keys for privileged identities and anything touching the control plane, and CBA only if you already run PKI. And prefer device-bound over synced passkeys wherever you need assurance about where the credential lives, because device-bound is what attestation and AAGUID allow-lists can actually verify.

Device-bound vs synced passkeys, in depth

This is the axis teams most often get wrong, so make the distinction explicit and policy-relevant.

Dimension Device-bound passkey Synced passkey
Key exportable? No — stays in TPM/secure element Yes — E2E-encrypted, synced across ecosystem devices
Survives device loss? No — re-register Yes — restore from the cloud keychain
Where the key can end up Exactly this device Any device signed into that cloud account (incl. personal)
Attestation Strong (real make/model) Often none or provider-generic
AAGUID allow-list usable? Yes Weakly (provider AAGUID, not per-device)
Sharing Not shareable Some providers allow sharing (e.g., family)
Enterprise assurance High Lower (depends on the sync ecosystem’s controls)
Typical examples Security key, WHfB, Authenticator device-bound passkey iCloud Keychain, Google Password Manager, 1Password
Recovery convenience Lower (need a spare) Higher (auto-restores)
Right for Privileged, regulated, high-assurance scopes Convenience-first workforce where sync ecosystem is trusted

The tension is assurance vs convenience. Synced passkeys are wonderful for the consumer and reduce lockouts dramatically — a lost phone doesn’t lose the credential. But for an enterprise, “the key can be anywhere the user’s personal cloud reaches” is a governance statement you may not be able to make about your privileged scope. And a synced credential typically can’t prove which device it’s on via attestation, so an AAGUID allow-list on device-bound hardware is defeated by allowing synced passkeys in the same scope.

The practical policy: allow synced passkeys for the general workforce where the convenience/lockout-reduction wins and the risk is acceptable; require device-bound credentials (security keys or WHfB) for privileged roles and any scope where attestation and key-location assurance are the point. Express that split as two authentication strengths bound to two Conditional Access scopes — the general scope accepts more, the privileged scope accepts only device-bound. Do not let synced passkeys silently satisfy a policy you built AAGUID allow-lists to enforce.

Enabling the methods: the Authentication methods policy

Enabling a method makes registration and use possible; it does not enforce anything. Do this in the Authentication methods policy (Entra admin center → Protection → Authentication methods → Policy), or via Graph so the config is reviewable, diffable, and repeatable in source control. Roll to a pilot ring (a security group), never “All users,” on day one.

Turn on FIDO2 (security keys and passkeys share this config)

Connect-MgGraph -Scopes "Policy.ReadWrite.AuthenticationMethod"

# Enable FIDO2 tenant-wide, allow self-service registration, no restrictions yet.
$fido2 = @{
  "@odata.type"                    = "#microsoft.graph.fido2AuthenticationMethodConfiguration"
  id                               = "Fido2"
  state                            = "enabled"
  isSelfServiceRegistrationAllowed = $true
  isAttestationEnforced            = $true     # we tighten scope in the AAGUID section
  includeTargets                   = @(
    @{ id = "<pilot-group-oid>"; targetType = "group"; isRegistrationRequired = $false }
  )
  keyRestrictions                  = @{
    isEnforced      = $false                   # tightened in step on key restrictions
    enforcementType = "allow"
    aaGuids         = @()
  }
}
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "Fido2" -BodyParameter $fido2

Enable Authenticator passkeys under the Microsoft Authenticator method surface, scoped to the pilot group, and enable Windows Hello for Business through your device configuration (Intune / group policy) — WHfB registration is driven at the device layer, not purely the auth-methods policy. The methods and how each is turned on:

Method Where you enable it Scope on day one Key control surface
FIDO2 security key Auth methods policy → FIDO2 Pilot group keyRestrictions, isAttestationEnforced
Authenticator passkey Auth methods policy → Microsoft Authenticator Pilot group Authenticator-specific + passkey profile
Windows Hello for Business Intune / GPO device config Pilot devices Device policy, TPM required
Temporary Access Pass Auth methods policy → TAP Onboarding admins Lifetime, one-time use
Certificate-based auth Auth methods policy → CBA Regulated group Certificate authorities, binding

The Authentication methods policy fields that matter

Field What it does Values Watch-out
state Enable/disable the method enabled / disabled Disabling removes ability to use it
includeTargets Groups the method applies to group OIDs / all_users Never all_users on day one
excludeTargets Groups to exclude group OIDs Exclude break-glass group
isSelfServiceRegistrationAllowed Users can self-register true/false true for adoption; false for admin-only
isAttestationEnforced Require valid attestation true/false true rejects unattested keys — test first
keyRestrictions.isEnforced Turn on AAGUID allow/block true/false If false, ANY key registers
keyRestrictions.enforcementType Allow-list or block-list allow/block allow = only listed models
isRegistrationRequired Force registration on target true/false Use campaigns instead for softer nudge

Authentication strengths and Conditional Access

Authentication strength is the policy object that says “this resource requires a method of at least this class,” independent of which specific keys are enabled tenant-wide. Entra ships three built-in strengths; you can also author custom ones.

The built-in strengths

Built-in strength Policy ID What satisfies it
Multifactor authentication 00000000-0000-0000-0000-000000000002 Any two factors (incl. password + push/OTP)
Passwordless MFA 00000000-0000-0000-0000-000000000003 WHfB, FIDO2 key, Authenticator passwordless, CBA
Phishing-resistant MFA 00000000-0000-0000-0000-000000000004 FIDO2 key, WHfB, CBA (multifactor) only

The Phishing-resistant MFA strength (…004) accepts exactly the phishing-resistant methods and rejects phone, SMS, TOTP, and Authenticator push. That rejection is the entire security property — a user who tries to satisfy it with a push is blocked and prompted for a real phishing-resistant method. That is by design and is exactly what you want.

Binding it to Conditional Access (report-only first)

Start with the highest-value target — privileged roles — in report-only, then expand. Always exclude break-glass.

Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess","Policy.Read.All"

$params = @{
  displayName = "CA-PR01 - Phishing-resistant MFA for admins"
  state       = "enabledForReportingButNotEnforced"     # report-only first
  conditions  = @{
    users = @{
      includeRoles = @(
        "62e90394-69f5-4237-9190-012177145e10"           # Global Administrator
      )
      excludeGroups = @("<break-glass-group-oid>")
    }
    applications = @{ includeApplications = @("All") }
  }
  grantControls = @{
    operator               = "OR"
    authenticationStrength = @{ id = "00000000-0000-0000-0000-000000000004" }
  }
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Run report-only for one to two weeks, review Insights & reporting to see who would have been blocked, fix their registration, then flip state to enabled. The rollout rings and cadence:

Ring Population State Duration Gate to next ring
0 — Pilot IT + volunteers (20–50) Report-only → enabled 1–2 weeks All pilot users PR-capable, zero surprise blocks
1 — Privileged Admin roles (~hundreds) Report-only → enabled 2 weeks 100% of privileged users have 2 FIDO2 keys
2 — High-value Finance, execs, sensitive apps Report-only → enabled 2–3 weeks Registration >95%, help-desk trained
3 — Workforce All users Report-only → enabled 4–8 weeks No target user left non-PR-capable
4 — Legacy shutdown Block legacy auth tenant-wide Report-only → enabled 1–2 weeks Confirmed no critical app on basic auth

Custom authentication strengths — keys only, no Hello

If you want to require FIDO2 security keys only (excluding WHfB) for the most sensitive scope — because admins must use portable hardware keys, not the workstation TPM — author a custom strength. This is also how you require device-bound over synced (by allowing only the specific method combinations that are device-bound).

$strength = @{
  displayName         = "PR - Hardware FIDO2 keys only"
  allowedCombinations = @("fido2")     # FIDO2 security key only; not windowsHelloForBusiness
}
$created = New-MgPolicyAuthenticationStrengthPolicy -BodyParameter $strength

$caAdmins = @{
  displayName = "CA-PR02 - Hardware FIDO2 for privileged roles"
  state       = "enabled"
  conditions  = @{
    users = @{
      includeRoles = @(
        "62e90394-69f5-4237-9190-012177145e10",   # Global Administrator
        "194ae4cb-b126-40b2-bd5b-6091b380977d"    # Security Administrator
      )
      excludeGroups = @("<break-glass-group-oid>")
    }
    applications = @{ includeApplications = @("All") }
  }
  grantControls = @{
    operator               = "OR"
    authenticationStrength = @{ id = $created.Id }
  }
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $caAdmins

The allowedCombinations values you can compose a custom strength from:

Combination value Method Phishing-resistant?
fido2 FIDO2 security key Yes
windowsHelloForBusiness WHfB Yes
x509CertificateMultiFactor CBA (multifactor) Yes
deviceBasedPush Authenticator passwordless push No (not PR)
password,microsoftAuthenticatorPush Password + push No
password,sms Password + SMS No
temporaryAccessPassOneTime One-time TAP No (bootstrap only)

A key nuance: use authentication context to require phishing-resistant on specific actions inside an app (e.g., a privileged operation) rather than the whole app, so you don’t force a hardware-key ceremony on low-risk reads. That is the persona/authentication-context design from the Conditional Access at scale article — pair the strength with a context tag for surgical enforcement.

Enforcing key restrictions: AAGUID allow-lists and attestation

Enabling FIDO2 lets any WebAuthn key register — including a cheap, unknown-provenance key bought online, or a synced consumer passkey. For privileged identities you want to constrain to vetted models. Every authenticator model has a stable AAGUID (Authenticator Attestation GUID); an allow-list pins registration to your approved hardware.

AAGUID allow-list

$fido2Restricted = @{
  "@odata.type"         = "#microsoft.graph.fido2AuthenticationMethodConfiguration"
  id                    = "Fido2"
  state                 = "enabled"
  isAttestationEnforced = $true
  keyRestrictions       = @{
    isEnforced      = $true
    enforcementType = "allow"                     # only these AAGUIDs may register
    aaGuids = @(
      "ee882879-721c-4913-9775-3dfcce97072a",     # example model A (get the real GUID from vendor)
      "fa2b99dc-9e39-4257-8f92-4a30d23c4118"      # example model B
    )
  }
}
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "Fido2" -BodyParameter $fido2Restricted

Get the real AAGUIDs from your vendor’s published list — never guess. The values above are illustrative. Validate the allow-list against the actual keys in a registration test before enforcing, or you will block your own pilot on day one.

Attestation — what it proves and what it costs

Attestation validates the key’s attestation statement against the FIDO Metadata Service (MDS) at registration, proving the key really is the make and model it claims, with non-exportable key material. Enforcement types you can request:

Attestation preference What Entra asks for What it proves Cost / risk
none No attestation Nothing about make/model Any key/synced passkey registers
indirect Anonymized attestation Model class, privacy-preserving Weaker binding
direct Full attestation Exact make/model via MDS Rejects keys without a recognized cert chain
enterprise Device-identifying attestation Ties to a specific enterprise-provisioned device Requires enterprise attestation support

The trade-off is real:

If you enforce attestation… You gain You risk
isAttestationEnforced = $true Only genuine, vetted, non-exportable keys register Otherwise-fine keys without an MDS-recognized cert chain are rejected
Combined with AAGUID allow-list Exactly your approved models, cryptographically proven Any procurement drift breaks registration until the list is updated
Tenant-wide Uniform assurance A single off-list batch strands a whole cohort
Privileged scope only Assurance where it matters Workforce can register broadly without the gate

Caution: isAttestationEnforced = $true will reject keys whose attestation can’t be validated against MDS, and some otherwise-fine keys ship without an attestation cert chain Entra recognizes. Synced passkeys generally present no usable attestation and will be rejected under enforcement — which is intended when you want device-bound only, and a lockout when you didn’t mean to exclude the workforce. Test with your exact procurement before turning it on, and scope it to where assurance is actually required.

The control surface is migrating

Microsoft is moving these controls into a passkey (FIDO2) profile model, and the standalone isAttestationEnforced / keyRestrictions properties on the FIDO2 configuration are being superseded (kept in sync during transition). Pin your tooling and re-read the resource type when you automate this, because the property surface is changing; hard-coding the old shape will silently drift. Treat the auth-methods policy as code you review each cycle, not a set-and-forget.

Enforce where assurance matters — not blindly tenant-wide

The single most common self-inflicted outage in this whole rollout is turning on tenant-wide attestation + allow-list, then discovering a cohort with off-list keys who now can’t register anything during the campaign and start snoozing the prompt indefinitely. The rule: scope attestation and key restrictions to the privileged population (via a group-targeted policy), and let the general workforce register approved keys/passkeys without the strict gate. You get assurance exactly where the blast radius justifies it.

Enrollment at scale: Temporary Access Pass and campaigns

You cannot enforce a method nobody has registered. Two mechanisms drive adoption, and one of them solves the bootstrap paradox.

Temporary Access Pass — the passwordless bootstrap

Temporary Access Pass (TAP) solves the chicken-and-egg problem: how does a user register their first passkey when you’re trying to kill passwords? A TAP is a time-limited, optionally one-time passcode an admin (or help desk via PIM) issues. The user signs in with the TAP and immediately enrolls a security key or passkey — no password ever involved. Wire TAP issuance into your joiner process so day-one is passwordless from first login.

# Enable TAP as a method (one-time use, tight lifetime)
$tapConfig = @{
  "@odata.type"            = "#microsoft.graph.temporaryAccessPassAuthenticationMethodConfiguration"
  id                       = "TemporaryAccessPass"
  state                    = "enabled"
  defaultLifetimeInMinutes = 60
  defaultLength            = 8
  isUsableOnce             = $true
  minimumLifetimeInMinutes = 60
  maximumLifetimeInMinutes = 480
  includeTargets           = @(@{ id = "<onboarding-group-oid>"; targetType = "group" })
}
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "TemporaryAccessPass" -BodyParameter $tapConfig

# Issue a one-time TAP to a user onboarding their first passkey
$pass = @{ isUsableOnce = $true; lifetimeInMinutes = 60 }
New-MgUserAuthenticationTemporaryAccessPassMethod -UserId "newhire@contoso.com" -BodyParameter $pass

Hand the TAP out of band — never over the same email channel you’re protecting, and verify the recipient’s identity before issuing (a TAP is a full credential for its lifetime; help-desk social engineering to obtain one is a real attack). TAP configuration knobs:

TAP setting What it does Default Range Guidance
defaultLifetimeInMinutes How long a TAP is valid 60 10–43,200 Short for onboarding (60)
defaultLength Passcode length 8 8–48 8+ is fine
isUsableOnce One-time vs multi-use false true/false true for security; multi-use only for multi-step setup
minimumLifetimeInMinutes Floor on lifetime 60 ≥10 Keep tight
maximumLifetimeInMinutes Ceiling on lifetime 480 ≤43,200 Cap to a shift, not days
includeTargets Who can be issued a TAP none groups Scope to onboarding/help-desk-served users

Registration campaigns — the nudge

A registration campaign nudges users at sign-in to set up the recommended passwordless method, with a snooze count, scoped to a group, excluding users who already have a passkey.

$campaign = @{
  registrationEnforcement = @{
    authenticationMethodsRegistrationCampaign = @{
      snoozeDurationInDays = 1
      state                = "enabled"
      excludeTargets       = @()
      includeTargets       = @(
        @{
          id                           = "<pilot-group-oid>"
          targetType                   = "group"
          targetedAuthenticationMethod = "microsoftAuthenticator"
        }
      )
    }
  }
}
Update-MgPolicyAuthenticationMethodPolicy -BodyParameter $campaign

The enrollment reporting gate

The reporting query is your enforcement gate: never flip a strength policy from report-only to enabled while the target population still contains users who are not passwordless-capable.

# Who still has no strong (passwordless) method registered?
az rest --method get \
  --url "https://graph.microsoft.com/v1.0/reports/authenticationMethods/userRegistrationDetails?\$filter=isPasswordlessCapable eq false&\$select=userPrincipalName,methodsRegistered,isMfaCapable" \
  --query "value[].{user:userPrincipalName, methods:methodsRegistered}" -o table

The enrollment-drive tools compared:

Mechanism Pushiness Bootstraps first credential? Best for
Temporary Access Pass Admin-issued, deliberate Yes New hires, first-credential, recovery
Registration campaign Soft nudge at sign-in, snoozable No (user still needs a method) Broad workforce adoption
isRegistrationRequired on method Hard requirement No When you must force registration
Conditional Access “register security info” Gate before resource access No Force setup before granting access

Break-glass FIDO2 accounts: the way back in

This is the part teams get wrong, and the part that ends careers. If a Conditional Access policy or a method outage locks out every admin, break-glass accounts are your way back in. Build two (so a single account compromise or expiry doesn’t strand you).

The design rules

Property Requirement Why
Account type Cloud-only *.onmicrosoft.com No dependency on federation or on-prem
Role Permanent Global Administrator (active, not PIM-eligible) No activation step or approver between you and recovery
Conditional Access Excluded from every CA policy (via an exclusion group) A locked-out tenant with break-glass also locked out is a resume event
Credential (password) 30+ char random, split-knowledge, offline in a safe No single person holds it; survives an insider
Credential (strong) A FIDO2 security key registered to each Break-glass need not mean weak — PR recovery without a CA dependency
Physical separation Keys stored separately from passwords No single physical breach yields both
Monitoring Any sign-in fires a high-severity alert A break-glass login nobody noticed = no monitoring
Testing Quarterly login + password rotation + alert-fired check An untested control is a hypothesis, not a control

The crucial nuance for this article: break-glass does not have to mean “weak.” A hardware FIDO2 key excluded from CA gives you phishing-resistant recovery without the CA dependency. You are not trading away security for availability; you are removing the policy dependency (which could be misauthored) while keeping a strong credential. Store each key physically separate from its account’s password.

Excluding break-glass correctly

Use a dedicated exclusion group and reference it in every CA policy’s excludeGroups, rather than listing user OIDs per policy (which drifts — someone adds a policy and forgets the exclusion). One group, referenced everywhere, is auditable in a single place.

# Create the exclusion group ONCE; add both break-glass accounts; reference it in every CA policy.
$grp = New-MgGroup -DisplayName "SG-BreakGlass-Exclude" -MailEnabled:$false `
  -SecurityEnabled:$true -MailNickname "sg-breakglass-exclude"

# Register a FIDO2 key to each break-glass account (done interactively via the portal /
# security-info flow while signed in as that account with a bootstrap TAP), then verify:
Get-MgUserAuthenticationFido2Method -UserId "bg1@contoso.onmicrosoft.com" |
  Select-Object Id, Model, DisplayName

Monitoring break-glass sign-ins

// Sentinel / Log Analytics: alert on ANY break-glass sign-in
SigninLogs
| where UserPrincipalName in~ ("bg1@contoso.onmicrosoft.com",
                               "bg2@contoso.onmicrosoft.com")
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName,
          ResultType, ResultDescription, ConditionalAccessStatus,
          AuthenticationRequirement
| order by TimeGenerated desc

Wire that to an analytics rule at severity High with a real paging action. Also alert on changes to the break-glass accounts or the exclusion group — a common attacker move is to add themselves to the exclusion group or reset a break-glass credential.

// Alert if the break-glass exclusion group membership changes, or a BG credential is touched
AuditLogs
| where OperationName in ("Add member to group", "Remove member from group",
                          "Reset user password", "Update user",
                          "User registered security info")
| where TargetResources has_any ("SG-BreakGlass-Exclude",
                                 "bg1@contoso.onmicrosoft.com",
                                 "bg2@contoso.onmicrosoft.com")
| project TimeGenerated, OperationName, InitiatedBy, TargetResources, Result

The quarterly rehearsal

Quarterly testing is mandatory. A break-glass account you have never tested is a hypothesis. Each quarter, run the drill and record it in the runbook:

Step Action What it validates
1 Retrieve password (split-knowledge) + key from the safe The physical process and access work
2 Sign in with each account using the FIDO2 key Password and the excluded-from-CA path
3 Confirm the sign-in was not challenged by strength policies The exclusion actually holds
4 Confirm the Sentinel alert fired and paged Monitoring works end to end
5 Perform a benign privileged read (e.g., list CA policies) The account still has GA rights
6 Rotate the password; re-split; return to safe Credential freshness
7 Record date, operators, outcomes in the runbook Auditable evidence of the control

Calendarize it. The single 02:00 incident where recovery works pays for every rehearsal.

Recovery: when a user loses their only authenticator

Passwordless raises the stakes on lost credentials — there’s no password to fall back to. Design the recovery paths before enforcement, per persona.

Situation Recovery path Prerequisite Assurance
User has a second registered method Sign in with the other method, re-register the lost one Enforce ≥2 methods at enrollment High (self-service, no help desk)
Privileged user loses one of two keys Use the second key; order a replacement Two keys mandatory for admins High
User has only one method (should be rare) Help-desk-issued TAP after identity proofing TAP enabled; strong proofing Medium (help-desk trust)
Synced passkey, lost one device Restore from cloud keychain on another device Synced ecosystem (iCloud/Google) Medium (ecosystem-dependent)
Device-bound platform (WHfB), device dead Re-enroll WHfB on the new device via TAP New managed device High
Everyone locked out (policy error) Break-glass account Break-glass built + rehearsed The last resort

The design principle: require at least two registered methods at enrollment so the common case is self-service recovery (use the other method), and reserve help-desk TAP for the genuinely single-method exception with strong identity proofing. For privileged users, two hardware keys is non-negotiable — one lives with them, one is the recovery. The help-desk TAP path is the social-engineering surface: verify identity out of band (a manager callback, a known-secret challenge, video with ID) before issuing, and alert on every TAP issued to a privileged account.

Windows Hello for Business interplay

WHfB is both a phishing-resistant method and a common source of confusion, because it overlaps with FIDO2 and has its own trust models.

WHfB is a WebAuthn platform credential in the device’s TPM — origin-bound and phishing-resistant, and it satisfies the built-in Phishing-resistant strength. But WHfB has deployment models (cloud Kerberos trust, key trust, cert trust for hybrid) that affect on-prem resource access, and those are orthogonal to the Entra sign-in phishing resistance. For the cloud sign-in that this article cares about, WHfB is a strong, free, device-bound authenticator; the trust-model complexity is about on-prem Kerberos/NTLM resource access.

WHfB aspect Relevance to phishing-resistant Entra sign-in Notes
WebAuthn credential in TPM Directly — this is the phishing-resistant factor Device-bound, attestable
Cloud Kerberos trust Indirect — for on-prem resource SSO Simplest hybrid model; recommended
Key trust / Cert trust Indirect — legacy hybrid on-prem access More moving parts (PKI for cert trust)
Windows Hello PIN The UV step (device-bound, not a password) PIN never leaves the device; not phishable
Multi-device Each device is a separate WHfB registration User with 3 PCs = 3 registrations

The interplay decisions:

Question Answer Why
Does WHfB satisfy phishing-resistant strength? Yes It’s a WebAuthn TPM credential
Should privileged admins rely on WHfB alone? No Prefer portable hardware keys (custom “fido2 only” strength)
Is the Windows Hello PIN a password? No Device-bound, TPM-protected, non-phishable
Does WHfB replace security keys? For daily workforce, largely; not for shared devices or admins WHfB is device-bound; keys are portable
WHfB + security key together? Yes — Hello daily, key for privileged/cross-device Belt and suspenders for high-value users

A practical stance: WHfB for the managed-PC workforce daily driver, security keys layered on for privileged access, shared devices, and cross-device login. Don’t force a false choice — WHfB and FIDO2 keys are complementary, and the strongest users have both.

Migrating off legacy MFA

This is a sequenced migration, not a switch. Getting the order wrong either leaves the AiTM hole open or locks you out.

The migration sequence

Phase Do this Do NOT yet Exit criteria
1. Foundations Build + rehearse break-glass; enable TAP Enforce any strength Break-glass tested, alert fires
2. Enable methods Turn on FIDO2/passkeys/WHfB for pilot Restrict AAGUIDs tenant-wide Pilot can register and sign in
3. Enforce pilot PR strength on pilot, report-only → enabled Touch the workforce Pilot 100% PR-capable
4. Privileged PR (or FIDO2-only) strength on admin roles Skip the two-keys rule Every admin has 2 keys, enforced
5. Campaign workforce Registration campaign + TAP for new hires Enforce before adoption Workforce registration >95%
6. Enforce workforce PR strength on all users, report-only → enabled Leave anyone non-PR-capable Reporting query returns empty
7. Shut legacy Block legacy auth; retire weak methods Forget dependent apps No basic-auth app breaks
8. Remove fallbacks Disable SMS/voice as satisfying methods Remove before PR is universal PR is the only path

Migrate authentication methods off the legacy policy

The legacy per-user MFA and Security Defaults surfaces are deprecated in favor of the Authentication methods policy and Conditional Access. Move method management into the new policy so everything is in one governable place, and use the migration guidance to flip the tenant from the legacy MFA/SSPR method management to the converged policy.

# Confirm which methods are enabled and their targets in the converged policy
Get-MgPolicyAuthenticationMethodPolicy |
  Select-Object -ExpandProperty AuthenticationMethodConfigurations |
  Select-Object Id, State

Shut down legacy authentication — it bypasses everything

Legacy/basic-auth protocols (POP, IMAP, SMTP AUTH, older Exchange ActiveSync) cannot do modern MFA at all, so they are a bypass around every strength you enforce. Block them explicitly with a separate, single-purpose policy — they will silently undermine your passwordless rollout otherwise.

$legacy = @{
  displayName = "CA-PR09 - Block legacy authentication"
  state       = "enabledForReportingButNotEnforced"     # report-only first!
  conditions  = @{
    users          = @{ includeUsers = @("All"); excludeGroups = @("<break-glass-group-oid>") }
    applications   = @{ includeApplications = @("All") }
    clientAppTypes = @("exchangeActiveSync","other")
  }
  grantControls = @{ operator = "OR"; builtInControls = @("block") }
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $legacy

Before enforcing, hunt for what still uses legacy auth so you don’t break a service account or an old app:

// Which sign-ins are using legacy auth clients? (find them before you block)
SigninLogs
| where TimeGenerated > ago(30d)
| where ClientAppUsed in ("Other clients", "IMAP4", "POP3", "SMTP", "Exchange ActiveSync",
                          "Authenticated SMTP", "MAPI Over HTTP")
| summarize count() by UserPrincipalName, ClientAppUsed, AppDisplayName
| order by count_ desc

Architecture at a glance

There is no diagram for this article; the architecture is a sequence of policy layers and a credential ceremony, and it reads more clearly as prose you can hold in your head than as boxes.

Picture the request path as three concentric gates around your tenant. The outermost gate is the credential ceremony. A user at a browser initiates sign-in; the browser (the WebAuthn client) constructs clientDataJSON stamped with the actual origin it is on, and the authenticator — a security key, the device TPM (Windows Hello for Business), or Microsoft Authenticator on the phone — verifies the human (PIN or biometric, the UV flag) and signs the server’s challenge with a private key that never leaves the hardware. Entra, the relying party, verifies the signature against the stored public key and checks that the origin matches. An AiTM proxy sits at a different origin, so it never gets past this gate: the browser won’t produce an assertion for it, and Entra would reject the mismatch. That is where credential phishing dies — at the outer gate, by the platform, without any human judgment involved.

The middle gate is the Authentication methods policy — which credentials are even allowed to exist. FIDO2 is enabled and, for the privileged scope, constrained by an AAGUID allow-list and attestation so only vetted, device-bound hardware can register. The workforce scope is looser (WHfB, Authenticator passkeys, approved keys); the privileged scope is tight (specific key models, attested, device-bound). The innermost gate is the authentication strength bound to Conditional Access — the object that says “to reach this resource you must have arrived via a phishing-resistant method.” Privileged roles hit a strength that accepts only FIDO2 keys; the general workforce hits the built-in phishing-resistant strength; and every policy excludes the break-glass group.

Off to the side, deliberately outside all three gates, sit the two break-glass accounts — cloud-only Global Admins, each with a FIDO2 key in a safe, excluded from every Conditional Access policy, wired to a high-severity alert. They are the escape hatch precisely because they don’t depend on the policy layer that could be misauthored. And underneath everything, a legacy-authentication block slams shut the basic-auth protocols that would otherwise tunnel around all three gates. Read left to right, the whole system is: prove origin-bound possession at the ceremony, allow only trusted credentials to exist, require the strong class to reach sensitive resources, keep one rehearsed way back in, and seal the bypass.

Real-world scenario

Meridian Health — a fictional but realistic hospital network — rolled phishing-resistant MFA to ~12,000 staff. The security team’s mandate came from a near-miss: an AiTM phish had captured a nurse-manager’s session (password + Authenticator push, all relayed) and the attacker had read a mailbox for two weeks before detection. Push-with-number-matching had not saved them. Leadership approved a passwordless program with hard phishing resistance.

The plan: knowledge workers on managed PCs would get Windows Hello for Business and Authenticator passkeys; the ~400 privileged accounts (domain admins, Entra admins, EHR super-users) would get hardware security keys, two each. The team authored a custom authentication strength (fido2 only, excluding Hello) bound to a Conditional Access policy targeting admin roles, and enabled an AAGUID allow-list for the two YubiKey models procurement had standardized on. They built two break-glass accounts, each with a FIDO2 key in the datacenter safe, excluded from every policy, wired to a Sentinel High alert.

Three things went wrong, and how they were fixed:

First, the constraint surfaced on the clinical floor. Nurses moved between shared workstations every few minutes, and the platform-passkey design assumed one user per device TPM — which broke the instant a second nurse tried to sign in on the same PC. WHfB is device-bound; it does not roam. Fix: the shared clinical workstations were moved to hardware security keys (portable — the key travels with the nurse, not the PC), and the team stopped trying to make WHfB fit genuinely shared hardware.

Second, they had set isAttestationEnforced = $true tenant-wide, and a batch of keys from a third vendor (bought before standardization) failed MDS attestation. A cohort of clinicians couldn’t register anything during the registration campaign and started snoozing the prompt indefinitely — the enrollment numbers stalled and nobody knew why until the reporting query showed a block of users stuck at isPasswordlessCapable = false. Fix: they moved attestation and key-restriction enforcement off the tenant-wide FIDO2 config and onto the privileged scope only, so the workforce could register approved keys/passkeys without the strict attestation gate that the off-list third-vendor keys tripped.

Third — the load-bearing detail — at 02:00 during a change window, a misauthored Conditional Access policy briefly blocked the entire admin group (an includeRoles change without the exclusion re-applied). Recovery worked only because both break-glass accounts were excluded from every policy and each had a FIDO2 key in the safe. The on-call retrieved a key, signed in, reverted the policy, and the Sentinel rule paged the secondary on-call exactly as designed — confirming, in the worst possible moment, that the rehearsed control was real. The post-incident review wrote down three lessons: scope attestation and key restrictions to where assurance is required; segment shared devices to portable keys early; and treat break-glass as the one control you rehearse on a schedule, not the one you hope you never need. The incident, as a timeline:

Time Event Effect Lesson
Week 1 WHfB rolled to clinical floor Second nurse on shared PC can’t sign in WHfB doesn’t roam — shared = keys
Week 2 Tenant-wide attestation enforced Off-list third-vendor keys rejected; cohort stuck Scope attestation to privileged only
Week 3 Reporting query run Block of users at isPasswordlessCapable=false found The reporting query is the gate
Week 4 Attestation moved to privileged scope Workforce enrollment resumes Assurance where blast radius justifies
Week 6, 02:00 Misauthored CA blocks admin group Total admin lockout — except break-glass Exclusion group + FIDO2 key in safe = recovery
Week 6, 02:07 Break-glass sign-in, policy reverted Recovered; Sentinel paged on-call Rehearsed break-glass is the last resort that works

Six months later, the AiTM phishing that started the whole program was demonstrably dead: red-team AiTM tests could relay the password but produced no valid assertion, and the phishing-resistant strength blocked every downgrade attempt. Privileged-account compromise via credential phishing went to zero.

Advantages and disadvantages

Phishing-resistant passwordless is the highest-assurance identity control available, but it has real operational costs. Weigh them honestly.

Advantages Disadvantages
Removes the entire credential-phishing class (AiTM, OTP relay, push fatigue) — the largest attack category Requires rolling a new credential to every human on messy, heterogeneous hardware
No shared secret to steal, no code to relay, no password to spray Lost-credential recovery is harder — no password fallback; must design recovery paths
Origin binding is platform-enforced, not user-judgment — users can’t “approve anyway” Break-glass must be built and rehearsed, or enforcement risks tenant lockout
Passwordless is faster and nicer for users (tap/biometric) — adoption lever Hardware keys cost money (₹2,000–6,000+ per key, plus replacement logistics)
Attestation + AAGUID allow-lists give cryptographic assurance of which hardware Attestation misconfigured tenant-wide can strand whole cohorts
Device-bound keys are non-exportable — can’t be extracted by malware Shared devices and kiosks don’t fit platform authenticators; need portable keys
Satisfies the strongest Conditional Access strength and audit/compliance asks Migration must be sequenced; wrong order leaves the hole open or locks you out
WHfB is free and already on managed Windows devices Synced passkeys trade attestation/assurance for convenience — governance nuance

The control is right for every organization eventually — this is where identity security is going — and urgent for anyone with privileged cloud roles or high-value targets (finance, executives, healthcare). It bites hardest when teams treat it as a toggle rather than a migration, skip break-glass rehearsal, enforce attestation blindly tenant-wide, or forget that legacy auth and token theft route around the strong factor. Every disadvantage is manageable — but only if you know it exists and sequence for it, which is the entire point of this runbook.

Hands-on lab

Stand up a phishing-resistant enforcement in a test tenant (never production for a first run), register a FIDO2 method, enforce a strength in report-only, and validate. You need a Microsoft Entra test tenant, Global Admin, a FIDO2 security key (or an Authenticator passkey on a phone), and Microsoft Graph PowerShell. Delete the policies at the end.

Step 1 — Connect and confirm you’re in the test tenant.

Connect-MgGraph -Scopes "Policy.ReadWrite.AuthenticationMethod",`
  "Policy.ReadWrite.ConditionalAccess","Policy.Read.All","UserAuthenticationMethod.ReadWrite.All"
(Get-MgContext).TenantId   # verify this is your TEST tenant, not prod

Step 2 — Create a pilot group and a break-glass exclusion group.

$pilot = New-MgGroup -DisplayName "SG-Pilot-Passwordless" -MailEnabled:$false `
  -SecurityEnabled:$true -MailNickname "sg-pilot-pwl"
$excl  = New-MgGroup -DisplayName "SG-BreakGlass-Exclude" -MailEnabled:$false `
  -SecurityEnabled:$true -MailNickname "sg-bg-excl"
"Pilot: $($pilot.Id)  Exclude: $($excl.Id)"

Expected: two group OIDs printed. Add your test user to SG-Pilot-Passwordless.

Step 3 — Enable FIDO2 for the pilot group (no restrictions yet).

$fido2 = @{
  "@odata.type"                    = "#microsoft.graph.fido2AuthenticationMethodConfiguration"
  id                               = "Fido2"
  state                            = "enabled"
  isSelfServiceRegistrationAllowed = $true
  isAttestationEnforced            = $false
  includeTargets = @(@{ id = $pilot.Id; targetType = "group"; isRegistrationRequired = $false })
  keyRestrictions = @{ isEnforced = $false; enforcementType = "allow"; aaGuids = @() }
}
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "Fido2" -BodyParameter $fido2

Step 4 — Register a FIDO2 method as your test user. Sign in to https://myaccount.microsoft.comSecurity infoAdd sign-in methodSecurity key (or Passkey in Microsoft Authenticator). Complete the WebAuthn ceremony (tap the key, set/enter its PIN). Then verify from Graph:

Get-MgUserAuthenticationFido2Method -UserId "testuser@yourtenant.onmicrosoft.com" |
  Select-Object Id, DisplayName, Model, AaGuid

Expected: at least one row with the key’s Model and AaGuid. Note the AAGUID — you’ll allow-list it next.

Step 5 — Enable TAP (so you can bootstrap without a password).

$tap = @{
  "@odata.type" = "#microsoft.graph.temporaryAccessPassAuthenticationMethodConfiguration"
  id = "TemporaryAccessPass"; state = "enabled"
  isUsableOnce = $true; defaultLifetimeInMinutes = 60
  includeTargets = @(@{ id = $pilot.Id; targetType = "group" })
}
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "TemporaryAccessPass" -BodyParameter $tap

Step 6 — Create the phishing-resistant strength CA policy in REPORT-ONLY.

$ca = @{
  displayName = "LAB-CA-PR - Phishing-resistant for pilot (report-only)"
  state       = "enabledForReportingButNotEnforced"
  conditions  = @{
    users        = @{ includeGroups = @($pilot.Id); excludeGroups = @($excl.Id) }
    applications = @{ includeApplications = @("All") }
  }
  grantControls = @{
    operator = "OR"
    authenticationStrength = @{ id = "00000000-0000-0000-0000-000000000004" }  # built-in PR
  }
}
$policy = New-MgIdentityConditionalAccessPolicy -BodyParameter $ca
"Policy: $($policy.Id)  state: $($policy.State)"

Expected: a policy ID; state enabledForReportingButNotEnforced.

Step 7 — Validate the report-only signal. Sign in as the pilot user with a non-PR method (password + push if available). Then check what would have happened:

// In Log Analytics (if the tenant streams SigninLogs): report-only result for the pilot policy
SigninLogs
| where TimeGenerated > ago(1h)
| mv-expand ca = todynamic(ConditionalAccessPolicies)
| where ca.displayName == "LAB-CA-PR - Phishing-resistant for pilot (report-only)"
| project TimeGenerated, UserPrincipalName, reportOnlyResult = ca.result,
          AuthenticationRequirement
| order by TimeGenerated desc

Expected: reportOnlyResult shows reportOnlyFailure for the push sign-in (it would have been blocked) and reportOnlySuccess when you sign in with the FIDO2 key. That is the enforcement gate proving itself.

Step 8 — Add an AAGUID allow-list (optional, using YOUR key’s AAGUID from Step 4).

$fido2.keyRestrictions = @{ isEnforced = $true; enforcementType = "allow"; aaGuids = @("<your-key-AAGUID>") }
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "Fido2" -BodyParameter $fido2

Now attempt to register a different key model — it should be refused. That’s the allow-list working.

Step 9 — Teardown. Remove everything so the test tenant is clean.

Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.Id
# Disable the methods you enabled (set state=disabled) or reset includeTargets to none:
$fido2.state = "disabled"; $fido2.keyRestrictions = @{ isEnforced=$false; enforcementType="allow"; aaGuids=@() }
Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
  -AuthenticationMethodConfigurationId "Fido2" -BodyParameter $fido2
Remove-MgGroup -GroupId $pilot.Id
Remove-MgGroup -GroupId $excl.Id

Expected: policy and groups gone; FIDO2 disabled. You’ve now walked the whole loop — enable, register, enforce report-only, prove the gate, restrict by AAGUID, tear down.

Common mistakes & troubleshooting

The failure modes here are operational, not cryptographic. Match your symptom, confirm the cause, apply the fix.

# Symptom Root cause How to confirm Fix
1 Users blocked; “you can’t get there from here” Strength enforced before users are PR-capable Reporting query returns non-empty isPasswordlessCapable=false Flip back to report-only; drive enrollment first
2 Any key registers despite “restrictions on” keyRestrictions.isEnforced = $false Get the FIDO2 config; check the flag Set isEnforced = $true, enforcementType = "allow"
3 A cohort can’t register anything Tenant-wide attestation rejects their (off-list) keys Reporting query; registration errors mention attestation Scope attestation to privileged only
4 Push still satisfies the “PR” policy CA grant control not bound to strength …004 Inspect the policy’s authenticationStrength.id Bind the phishing-resistant strength ID
5 Admin group locked out Misauthored CA (includeRoles without exclusion) Sign-in logs show admin blocks; policy diff Use break-glass; re-apply exclusion group
6 Second nurse can’t sign in on shared PC WHfB is device-bound, doesn’t roam Only first user’s WHfB works on that TPM Move shared devices to portable FIDO2 keys
7 AAGUID allow-list blocks the intended key Wrong/guessed AAGUID in the list Compare Get-MgUserAuthenticationFido2Method AaGuid to the list Use the real AAGUID from the key/vendor
8 New hire can’t do first sign-in No TAP path; password-only bootstrap that you disabled User has no method and no TAP Enable TAP; wire into joiner process
9 Rollout “done” but breaches continue Legacy auth or token theft bypasses PR Legacy-auth KQL shows POP/IMAP/SMTP; token-theft signals Block legacy auth; add token protection
10 Break-glass challenged by a policy Break-glass not excluded from that policy Quarterly test shows a strength challenge Add break-glass group to every policy’s excludeGroups
11 Synced passkey satisfies device-bound-only scope Custom strength allows methods that permit sync Assertion from a synced credential succeeds Restrict allowed combinations to device-bound only
12 Attestation enforcement rejects a good key Key ships without an MDS-recognized cert chain Registration fails; MDS lookup finds no chain Choose attested models; test procurement first
13 Users stuck at the WebAuthn prompt Old browser/OS without WebAuthn or CTAP2 support Registration UI errors or hangs Update browser/OS; use supported client
14 Break-glass sign-in didn’t alert KQL rule not firing / no paging action Test sign-in produced no alert Fix the analytics rule; add a paging action; test

The one meta-lesson across all fourteen: the reporting query and the report-only mode are your safety rails. Every “we locked people out” story is someone who enforced before the report-only signal was clean. Never skip the gate.

Best practices

Security notes

Phishing-resistant credentials are the foundation, not the whole wall. Layer the rest:

Control Why it matters even with PR auth How
Token protection / bound sessions PR stops credential phishing; token theft still steals the session Enable token protection in CA; short session lifetimes
Device compliance in CA A compromised endpoint rides the authenticated session Require compliant/hybrid-joined device for sensitive scopes
Sign-in / user risk (ID Protection) Anomalous sign-in even with a valid key warrants step-up Risk-based CA alongside the strength policy
OAuth consent governance Consent phishing needs no credential at all Admin consent workflow; restrict user consent
Least privilege + PIM Fewer standing admins = smaller phishing target JIT elevation; eligible not active
Break-glass hardening The escape hatch is itself a target Exclusion group, physical key/password separation, alerting
Attestation for privileged Prevents unknown-provenance keys in the crown-jewels scope direct/enterprise attestation + AAGUID allow-list
Legacy auth block Basic auth tunnels around modern MFA entirely Single-purpose CA block policy
Monitoring & hunting Detect the residual (token theft, consent, insider) Sign-in/audit KQL, UEBA, hunting notebooks

The identity-security posture this fits into is broader — see Zero Trust on Microsoft Entra: Conditional Access + PIM, Step by Step, Zero Trust Architecture Blueprint: Identity, Network, and Data Pillars, and for detection KQL Threat Hunting Playbooks: MITRE ATT&CK Mapping, UEBA, and Hunting Notebooks. Workload identities need the same rigor via a different mechanism — Locking Down Workload Identities: Conditional Access, Risk Detection, and Going Secretless.

Cost & sizing

The bill here is mostly hardware keys and licensing, and both are small next to the breach they prevent.

Cost driver Rough figure Notes
FIDO2 security key (per unit) ₹2,000–6,000+ / ~$25–70+ Varies by model (USB-A/C, NFC, biometric)
Keys per privileged user 2 (primary + recovery) Non-negotiable for admins
Keys per workforce user (if used) 0–1 Many workforce users use WHfB/passkeys (free)
Windows Hello for Business Free Uses the device TPM; no per-user cost
Authenticator passkeys Free App on the user’s phone
Conditional Access + auth strengths Entra ID P1 P1 required for CA; likely already licensed
ID Protection (risk-based CA) Entra ID P2 Only if you add risk policies
Break-glass keys 2 × key cost Two accounts, two keys in the safe
Replacement/logistics Ongoing Loss/replacement process, shipping, help desk

Sizing guidance:

Population Recommended spend Rationale
~400 privileged users 800 keys (2 each) Two-key rule; portable, attestable
12,000 workforce (managed PCs) Mostly free (WHfB) + a pool of keys WHfB free; keys for shared/BYOD/edge cases
Frontline / shared devices Keys per person or per shift Portable keys travel with the person
Break-glass 2 keys Cheapest insurance you’ll ever buy

The framing that wins budget: the cost of the keys is trivially small next to the cost of one AiTM breach (incident response, regulatory exposure, business email compromise losses). WHfB and Authenticator passkeys make the workforce rollout essentially free; the hardware cost concentrates on the privileged and shared-device populations where the assurance is worth it. And enforcement itself is cheaper to operate than legacy MFA once it’s in — fewer resets, fewer help-desk calls about lost phones (with two methods registered), and no push-fatigue triage.

Interview & exam questions

Q1. Why is FIDO2 phishing-resistant when push-with-number-matching is not? FIDO2 binds the credential to the origin: the browser constructs clientDataJSON with the actual origin and the authenticator signs over the RP-ID hash, so a proxy at a different origin can’t produce a valid assertion and Entra rejects the mismatch. Number matching still relies on the human relaying an approval, which an AiTM proxy forwards in real time. (Relevant: SC-300, SC-100.)

Q2. What’s the difference between UP and UV in a WebAuthn assertion, and which does passwordless require? UP (user presence) means a human was present (a tap); UV (user verification) means the human was verified via PIN/biometric/device unlock. Passwordless requires UV, because the verification is the factor that makes the single ceremony multi-factor.

Q3. Device-bound vs synced passkeys — when would you require device-bound? Device-bound keys are non-exportable and attestable; synced passkeys copy the key across a cloud ecosystem for convenience but usually lack meaningful attestation. Require device-bound for privileged/regulated scopes where key-location assurance and attestation are the point; allow synced for the general workforce where lockout-reduction wins.

Q4. What does the built-in Phishing-resistant MFA strength accept, and what does it reject? It accepts FIDO2 security key, Windows Hello for Business, and certificate-based auth (multifactor); it rejects phone, SMS, TOTP, and Authenticator push. The rejection is the security property.

Q5. Why register a FIDO2 key to a break-glass account rather than leaving it password-only? Because break-glass need not be weak: a hardware key excluded from Conditional Access gives phishing-resistant recovery without the policy dependency that could itself be misauthored. You remove the CA dependency, not the credential strength.

Q6. What does attestation prove, and what’s the risk of enforcing it tenant-wide? Attestation validates the key’s make/model and non-exportable key material against the FIDO Metadata Service. Enforced tenant-wide, it rejects any key without an MDS-recognized cert chain — including a cohort’s off-list keys — stranding them. Scope it to the privileged population.

Q7. What’s an AAGUID and how do you use it? The Authenticator Attestation GUID is a stable model identifier. You put approved models’ AAGUIDs in an allow key-restriction list so only vetted hardware may register — but you must use the real AAGUID from the vendor and test before enforcing.

Q8. How does a Temporary Access Pass solve the passwordless bootstrap problem? A TAP is a time-limited (optionally one-time) passcode an admin issues; the user signs in with it and immediately registers their first passkey — no password ever involved. It’s the joiner-process credential for day-one passwordless.

Q9. Why must you enforce a strength in report-only first, and what gates the switch to enabled? Report-only shows who would be blocked without blocking them, so you find and fix non-PR-capable users. The gate to enabling is the reporting query returning no users at isPasswordlessCapable = false in the target scope.

Q10. How does Windows Hello for Business relate to FIDO2, and should admins rely on it alone? WHfB is a WebAuthn platform credential in the device TPM — phishing-resistant and satisfying the built-in strength. Admins should not rely on it alone because it’s device-bound (doesn’t roam) and you want portable hardware keys for privileged access; use a custom fido2-only strength for that scope.

Q11. Why must you block legacy authentication as part of a passwordless rollout? Basic-auth protocols (POP, IMAP, SMTP AUTH, older EAS) can’t do modern MFA at all, so they bypass every strength you enforce. Block them explicitly, after hunting for dependent apps/service accounts so you don’t break them.

Q12. FIDO2 is deployed and enforced — name two attacks it does NOT stop. Token/session theft (stealing the issued cookie post-authentication via malware/infostealer) and consent phishing (tricking a user into granting an OAuth app, which needs no credential). Both need separate controls (token protection, consent governance).

Quick check

  1. What single property makes a credential phishing-resistant, and which check in the WebAuthn assertion enforces it?
  2. Which three methods satisfy the built-in Phishing-resistant MFA strength (…004), and which common method does it reject?
  3. You enabled FIDO2 with keyRestrictions.enforcementType = "allow" but any key still registers — what’s wrong?
  4. Why should a break-glass account have a FIDO2 key and be excluded from every Conditional Access policy?
  5. What’s the difference between a device-bound and a synced passkey, and which is attestable?

Answers

  1. Origin binding. The authenticator signs over the RP-ID hash and the browser stamps the real origin into clientDataJSON; Entra verifies the origin matches (and the signature and challenge), so a proxy at a different origin can’t produce a usable assertion. Human relay of a code/push has no such check.
  2. FIDO2 security key, Windows Hello for Business, and certificate-based auth (multifactor). It rejects Authenticator push (and SMS/voice/TOTP) — that rejection is the point.
  3. keyRestrictions.isEnforced is still $false. Setting enforcementType without isEnforced = $true leaves restrictions off, so any WebAuthn key registers. Set isEnforced = $true.
  4. The FIDO2 key gives phishing-resistant recovery (break-glass need not be weak); the CA exclusion removes the policy dependency — if a Conditional Access policy is misauthored and locks out all admins, the excluded break-glass account still gets in. You keep the strong credential and remove the failure mode.
  5. A device-bound passkey’s private key is non-exportable and stays on the device (security key, TPM) — attestable via make/model. A synced passkey is E2E-encrypted and copied across a cloud ecosystem’s devices for convenience — usually not meaningfully attestable. Require device-bound where assurance matters.

Glossary

Next steps

FIDO2passwordlesspasskeysWebAuthnauthentication-strengthbreak-glassWindows HelloEntra
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading