A second factor where the risk is.
Multi-factor authentication enforced as pipeline policy — not scattered through controller code — with the second factor required exactly where the risk lives and selectively exempted where it does not. The 2026 edge moves the factor itself toward phishing-resistant passkeys and risk-adaptive prompts without changing where enforcement happens.
1. MFA as policy, not per-controller code
MFA fails in practice when it is a per-endpoint afterthought: one controller checks it, the next forgets, and the gap is invisible until it is exploited. B5 Secure makes the second factor a pipeline policy. You declare which operations, identities, or risk conditions require step-up, and the requirement is enforced uniformly before the handler runs. There is no path that “forgets” to ask, because asking is not the handler’s job.
Equally important is the inverse: the policy can selectively exempt specific users, operations, or trusted networks. Onboarding flows, low-risk reads, and machine identities on allow-listed networks are not forced through a human second factor that does not apply to them. The factor is required where the risk concentrates and absent where it would only add friction.
2. Today: enforced, expiring, exemptible
The proven core delivers a second factor with email-delivered codes, configurable per-session and inactivity expiry, and the exemption model above. Expiry is the quiet workhorse: a satisfied factor is not satisfied forever, so a stolen session that sat idle is challenged again rather than trusted indefinitely. The whole mechanism is part of the account lifecycle B5 ships — registration, login, forgot-password, and verification — so the security-sensitive flows are not hand-rolled per application.
3. The 2026 edge: phishing-resistant factors
Email and SMS codes are shared secrets a convincing phishing page can harvest in real time. The 2026 extension adds phishing-resistant factors as first-class options: FIDO2 / WebAuthn passkeys, where the authenticator signs a challenge bound to the origin so a credential phished on a look-alike domain is simply invalid, and TOTP (RFC 6238) for authenticator-app codes. These slot into the same policy surface — you are changing which factor satisfies the requirement, not where the requirement is enforced.
Origin binding is what makes passkeys phishing-resistant: the signature only verifies for the registered relying-party origin. A real-time phishing proxy on a different domain cannot relay it — the factor that defeats the most common credential attack is also the one with the least user friction.
4. Risk-adaptive step-up
Not every action deserves the same challenge. The adaptive model raises the bar with risk: a new device, an unfamiliar geo or ASN, an anomalous velocity, or a high-impact operation triggers step-up, while routine actions from a known posture proceed. The signals come from the same place the adaptive identity firewall reads them, so step-up decisions and network decisions share one view of risk rather than two disconnected ones.
5. The calling convention
You express the requirement declaratively; the pipeline enforces it and records satisfaction against the session.
// MFA is policy: required where the risk is, exempt where it isn't
services.AddB5SecurityKit(o => {
o.Mfa.Factors = MfaFactor.Passkey | MfaFactor.Totp | MfaFactor.EmailCode;
o.Mfa.Expiry = SessionExpiry.Inactivity(TimeSpan.FromMinutes(15));
o.Mfa.StepUp = RiskPolicy.NewDevice | RiskPolicy.GeoVelocity;
});
// High-impact operation always demands a satisfied second factor
[RequireMfa]
[Permission("payouts.approve")]
public async Task ApprovePayout(PayoutId id) => ...;6. What an attacker actually gets
A phished email or password alone reaches nothing privileged: the pipeline still demands the second factor. With passkeys, a real-time phishing proxy cannot relay the factor because the signature will not verify off-origin. Push-fatigue and SIM-swap paths are mitigated by preferring origin-bound passkeys and TOTP over SMS. A stolen but idle session is re-challenged on expiry. And because enforcement is central, there is no forgotten endpoint that quietly skips the check.
7. Where this lands in an audit
This is the control behind logical access and authentication assurance questions. Phishing-resistant factors map to NIST SP 800-63B authenticator assurance (AAL2, and AAL3 with hardware passkeys), and the uniform, policy-based enforcement is exactly what SOC 2 CC6.1 and PCI DSS strong-authentication requirements look for — with the bonus that you can evidence enforcement centrally rather than auditing every controller.
Next: Granular Authorization — authorize the action and the data →