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:
- Explain the WebAuthn registration and assertion ceremonies and the CTAP2 authenticator protocol precisely enough to say why a FIDO2 credential cannot be phished, including the roles of the relying party ID (RP ID),
clientDataJSON, the origin check, the challenge, and the user-presence/user-verification flags. - Distinguish device-bound from synced passkeys — key portability, attestation implications, recovery model, and the exact scenarios where a synced consumer passkey is and is not acceptable for an enterprise.
- Choose deliberately between FIDO2 security keys, platform authenticators (Windows Hello for Business, Face/Touch ID), and Microsoft Authenticator passkeys per persona, with the operational trade-offs of each.
- Model the Entra Authentication methods policy, the three built-in authentication strengths, and custom strengths, and bind a phishing-resistant strength to Conditional Access correctly — report-only first, break-glass excluded.
- Enforce key restrictions with AAGUID allow-lists and attestation, know exactly what attestation proves and what it costs, and track the migration of that control surface into the passkey-profile model.
- Drive enrollment at scale: Temporary Access Pass for first-credential bootstrap, registration campaigns, new-hire day-one passwordless, and the reporting query that gates enforcement.
- Design two break-glass FIDO2 accounts with the right exclusions, monitoring, and a quarterly rehearsal, and reason about recovery when a user loses their only authenticator.
- Sequence a migration off legacy MFA — including the Windows Hello for Business interplay and shutting down legacy authentication that bypasses everything.
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.com → Security info → Add sign-in method → Security 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
- Build and rehearse break-glass before you enforce anything. Two cloud-only Global Admins, each with a FIDO2 key in a safe, excluded from every CA policy via a single exclusion group, wired to a high-severity paging alert, tested quarterly.
- Enforce in report-only first, always. Bind the strength in
enabledForReportingButNotEnforced, watch Insights for one to two weeks, fix registrations, then flip toenabled. - Gate enforcement on the reporting query. Never move a strength to enabled while the target population still has users at
isPasswordlessCapable = false. - Require at least two registered methods at enrollment so recovery is self-service; two hardware keys for privileged users, non-negotiable.
- Scope attestation and AAGUID allow-lists to where assurance matters — privileged identities — not blindly tenant-wide, or you’ll strand cohorts.
- Prefer device-bound over synced passkeys for high-assurance scopes; allow synced for the general workforce where convenience and lockout-reduction win.
- Use hardware keys for privileged, shared, and BYOD-unmanaged; WHfB/passkeys for the managed-PC workforce. Don’t force platform authenticators onto shared hardware.
- Author a custom
fido2-only strength for the most sensitive scope so admins use portable keys, not the workstation TPM. - Use authentication context to require phishing-resistant on sensitive actions, not the whole app, so low-risk reads aren’t burdened.
- Block legacy authentication as a separate, single-purpose policy — it bypasses every strength you build.
- Wire TAP into the joiner process so day-one is passwordless; hand TAPs out of band and verify identity before issuing.
- Treat the Authentication methods policy as code — review it each cycle, because the attestation/key-restriction surface is migrating to the passkey-profile model.
- Alert on changes to break-glass accounts and the exclusion group, not just sign-ins — attackers target the escape hatch.
- Remove weak fallback methods (SMS/voice) only after PR is universal, so you don’t remove the ladder before everyone’s off it.
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
- What single property makes a credential phishing-resistant, and which check in the WebAuthn assertion enforces it?
- Which three methods satisfy the built-in Phishing-resistant MFA strength (
…004), and which common method does it reject? - You enabled FIDO2 with
keyRestrictions.enforcementType = "allow"but any key still registers — what’s wrong? - Why should a break-glass account have a FIDO2 key and be excluded from every Conditional Access policy?
- What’s the difference between a device-bound and a synced passkey, and which is attestable?
Answers
- 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. - 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.
keyRestrictions.isEnforcedis still$false. SettingenforcementTypewithoutisEnforced = $trueleaves restrictions off, so any WebAuthn key registers. SetisEnforced = $true.- 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.
- 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
- WebAuthn — The W3C browser/JavaScript API (
navigator.credentials) for creating and using public-key credentials; the client side of FIDO2 and the layer that enforces the origin check. - CTAP2 (Client to Authenticator Protocol 2) — The protocol between the platform (browser/OS) and the authenticator (security key, TPM); handles user verification and signing.
- FIDO2 — WebAuthn + CTAP2 together: the standard for phishing-resistant public-key credentials.
- RP ID (Relying Party ID) — The domain a credential is scoped to (
login.microsoftonline.com); a credential is unusable at any other origin. - Passkey — Umbrella term for a discoverable FIDO2 credential; may be device-bound (non-exportable) or synced (copied across a cloud ecosystem).
- Device-bound passkey — A credential whose private key cannot leave the device (security key, WHfB, Authenticator device-bound passkey); attestable, but lost with the device.
- Synced passkey — A credential the provider syncs (E2E-encrypted) across the user’s devices; survives device loss but usually lacks meaningful attestation.
- AAGUID (Authenticator Attestation GUID) — A stable identifier of an authenticator model, used in allow/block key restrictions.
- Attestation — A cryptographic statement proving an authenticator’s make/model and non-exportable key material, validated against the FIDO Metadata Service.
- FIDO Metadata Service (MDS) — The FIDO Alliance registry of authenticator metadata and attestation roots used to validate attestation statements.
- User Verification (UV) — The assertion flag indicating the human was verified (PIN/biometric); required for passwordless.
- User Presence (UP) — The assertion flag indicating a human was present (a tap); second-factor level, not full MFA alone.
- Authentication strength — An Entra policy object listing the method combinations that satisfy it; bound to Conditional Access to require a class of method.
- Authentication methods policy — The converged Entra policy controlling which methods are enabled, for whom, and with what restrictions.
- Temporary Access Pass (TAP) — A time-limited, optionally one-time passcode used to bootstrap a first passkey (or recover) without a password.
- AiTM (Adversary-in-the-Middle) — A phishing technique that proxies the real IdP to relay factors and steal the post-authentication session token.
- Windows Hello for Business (WHfB) — A platform authenticator binding a WebAuthn credential to the device TPM, unlocked by PIN/biometric.
- Break-glass account — A cloud-only emergency Global Admin, excluded from Conditional Access, used to recover from a tenant lockout.
- Certificate-based authentication (CBA) — PKI-cert (often smart-card) sign-in; phishing-resistant when configured as multifactor.
Next steps
- Designing Conditional Access at Scale: A Persona-Based Policy Framework with Authentication Context and Filters — where the strength policies live and how to scope them by persona and action.
- Engineering Break-Glass Emergency Access Accounts in Entra ID: Exclusions, Hardening, and Tamper-Evident Monitoring — the full break-glass hardening and monitoring deep dive.
- Privileged Identity Management and PAM Architecture: Just-in-Time Access at Scale — reduce the privileged attack surface the phishing-resistant policy protects.
- Operationalizing Entra ID Protection: Risk-Based Conditional Access, Detection Tuning, and Risk Investigation — add risk signals alongside the strength policy for step-up.
- Gating Microsoft 365 with Endpoint Conditional Access: Compliance Policies, Device Filters, and Require-Compliant Enforcement — pair phishing-resistant auth with device compliance to close the token-theft gap.