Not all second factors are equal, and the difference is not convenience. Some can be handed to an attacker by a person who is trying to do the right thing, and some cannot.
A code from an authenticator app, read off a screen and typed into a page, can be typed into the wrong page. A hardware key or a passkey is bound to the origin it was registered with, so it will not produce anything usable for a site that is not yours. That is the whole distinction, and it is the one that decides whether your multi-factor survives a competent phishing attempt.
This post is what that means in practice. For whoever is choosing which factors to allow.
How the codes get taken
The modern attack does not need to break anything. A proxy sits between the user and your login page, relays everything in real time, and collects what passes through.
The user receives a convincing link, lands on the proxy, sees your genuine login page because the proxy is fetching it, enters their password and their code, and the proxy forwards both. Your service authenticates successfully, issues a session, and the proxy keeps it.
Every factor that consists of a value the user reads and types falls to this: codes from an app, codes by text message, codes by email. So does push approval, because the user gets a prompt for a login they believe is theirs and approves it.
Number matching on push approval helps, because the user has to read a number from the attacker's page and enter it in their app, which adds a step where something can look wrong. It is an improvement and it is still a person deciding under pressure.
Why origin binding is different
A passkey or a hardware key produces a signature over the site's origin. Presented with yourcompany.example.com.attacker.example, it produces something that is not valid for your site, because the origin is part of what it signs.
There is nothing for the user to read out, nothing to type, and nothing to relay. The proxy attack does not fail because the user noticed; it fails because the cryptography does not cooperate.
That is the property worth paying for, and it is a categorical difference rather than an incremental one.
Where to require it first
Full rollout is a project. The order that gets most of the value:
Your own administrative accounts. Identity provider admins, cloud accounts, source host owners, anything that can grant access to others. A handful of people, and the highest consequence.
Anyone who can deploy or access production. Same reasoning, larger group.
Package publishing and signing. An account that can publish to a registry is a supply chain credential, and several ecosystems now require or strongly encourage strong factors for exactly this reason.
Then everyone, as you can.
The first two are usually under twenty people, and doing only those removes most of the realistic risk for a cost of a few hardware keys.
The recovery problem is the real work
This is where phishing-resistant deployments fail, and it deserves more thought than the rollout.
A hardware key can be lost, and a passkey lives in a platform account that can itself be lost. If your recovery path falls back to a code by text message, you have built a strong front door with the old lock on the side, and an attacker will use the side.
What works: enrol two factors from the start, so losing one is not an emergency. A hardware key plus a passkey, or two keys, one of which lives somewhere safe. Then recovery is a rare administrative act rather than a routine flow, and it can be slow and verified in person or by video, because it should almost never happen.
The remaining gaps
Being honest about what this does not solve:
Session theft after authentication. A stolen session cookie does not need a factor. Bind sessions to a device where you can, keep lifetimes short, and re-authenticate for sensitive actions.
Consent phishing. An attacker who gets a user to approve an OAuth application does not need their credentials at all, which is the connected-app problem rather than an authentication one.
Registration. If a user can enrol a factor without proving who they are, the attacker enrols theirs. Enrolment deserves the same care as recovery.
What to check
# Which factors does your identity provider currently allow?
# Which are actually in use, by account, and specifically for admins?
# Is there a fallback to a weaker factor, and does it apply to admins?
# What is your recovery path, and does it end in a text message?
The fourth question is the one that most often undoes the rest.
The concession
Hardware keys cost money, get lost, and are genuinely awkward for a distributed team or a workforce using shared devices. Passkeys remove most of the cost and tie recovery to a platform account, which is a dependency some organisations will not accept.
So the proportionate position is to require phishing-resistant factors where the consequence justifies the friction, which is administrative and production access, and to keep app-based codes for everyone else rather than letting a perfect standard delay a good deployment. App codes are much better than nothing, and the failure mode to avoid is spending a year designing a universal rollout while your administrators are still on codes.
The implication
The question is not whether you have multi-factor authentication. It is whether any of your factors can be relayed by somebody standing in the middle.
If your administrators can be phished through a proxy, the rest of your authentication design is a detail.