Skip to main content
Back to blog
April 28, 2026|8 min read

Multi-Factor Authentication Guide: MFA Types, Deployment & Passkeys in 2026

Multi-factor authentication is the most impactful security control available to web applications. This guide covers every MFA type, deployment strategies, and passkeys.

ZeriFlow Team

1,675 words

Multi-Factor Authentication Guide: MFA Types, Deployment & Passkeys in 2026

Multi-factor authentication reduces account compromise risk by over 99% for automated attacks. Yet deployment at scale — across diverse user bases, legacy systems, and varying threat models — requires careful planning. This guide covers MFA types, how to choose between them, deployment strategies, and the emerging passkeys standard that may replace traditional MFA entirely.

Check your site's security configuration: Free ZeriFlow scan in 60 seconds →

MFA vs 2FA: The Distinction That Matters

Two-factor authentication (2FA) is a specific form of multi-factor authentication that uses exactly two factors. MFA is the broader term covering two or more. The distinction matters because three-factor authentication (password + TOTP + hardware key) is appropriate for high-privilege access like production infrastructure, while two factors are sufficient for most user accounts.

The three factor categories: - Something you know: password, PIN, security question - Something you have: authenticator app, hardware key, phone (SMS) - Something you are: biometric (fingerprint, face recognition)

True MFA requires factors from at least two different categories. Two passwords is not 2FA. A password plus a TOTP code is 2FA (know + have).

TOTP: The Baseline Standard

TOTP (Time-based One-Time Password, RFC 6238) app-based authentication is the recommended baseline for most web applications. It is free, does not require a phone number, works offline, and is supported by dozens of authenticator apps (Google Authenticator, Authy, 1Password, Bitwarden).

For implementation details and code examples, see our two-factor authentication setup guide.

Key TOTP design decisions for large-scale deployment:

javascript
// Support multiple TOTP devices per user account
async function addTOTPDevice(userId, deviceName) {
  const secret = speakeasy.generateSecret({ length: 32 });
  
  await db.mfaDevices.create({
    userId,
    type: 'totp',
    name: deviceName,
    secret: encrypt(secret.base32),
    createdAt: new Date(),
    lastUsedAt: null,
    verified: false
  });
  
  return { secret: secret.base32, qrUrl: secret.otpauth_url };
}

// Verify against ALL user's active TOTP devices
async function verifyAnyTOTP(userId, token) {
  const devices = await db.mfaDevices.findActive(userId, 'totp');
  
  for (const device of devices) {
    const valid = speakeasy.totp.verify({
      secret: decrypt(device.secret),
      encoding: 'base32',
      token,
      window: 1
    });
    if (valid) {
      await db.mfaDevices.update(device.id, { lastUsedAt: new Date() });
      return true;
    }
  }
  return false;
}

Push MFA: Convenience at a Cost

Push authentication (Duo, Microsoft Authenticator, Okta Verify) sends a push notification to the user's phone. The user taps "Approve" or "Deny" rather than typing a code.

The usability advantage is real — fewer failed attempts from typos, faster authentication. But push MFA introduces MFA fatigue attacks: an attacker who has valid credentials sends repeated push notifications hoping the user approves one by mistake (or to stop the notifications). In 2022, Uber was breached this way.

Mitigations: - Enable number matching: the app shows a 2-digit code, the push notification shows the same code, the user must match them before approving. - Limit push notifications: lock the account after 3 denied pushes within 5 minutes. - Add context to push notifications: "Login request from Germany — was this you?"

javascript
// Push MFA with context
async function sendPushChallenge(userId, req) {
  const challengeId = crypto.randomUUID();
  const context = {
    ip: req.ip,
    userAgent: req.headers['user-agent'],
    location: await geolocate(req.ip),
    timestamp: new Date().toISOString()
  };

  await db.mfaChallenges.create({
    id: challengeId,
    userId,
    type: 'push',
    context,
    status: 'pending',
    expiresAt: new Date(Date.now() + 5 * 60 * 1000),
    numberMatch: Math.floor(Math.random() * 100) // 2-digit code
  });

  await pushProvider.sendNotification(userId, {
    title: 'Login Request',
    body: `From ${context.location?.city || context.ip}. Number: ${challenge.numberMatch}`,
    challengeId
  });

  return { challengeId, numberMatch: challenge.numberMatch };
}

Hardware Security Keys: Phishing-Proof MFA

FIDO2 / WebAuthn hardware keys are the only MFA method that is cryptographically phishing-proof. The browser binds authentication to the exact origin using public key cryptography. A phishing site on yourapp-security.com cannot get a valid assertion for yourapp.com.

In 2026, WebAuthn support is available in all major browsers without plugins. The API is straightforward:

javascript
// Registration
app.post('/mfa/webauthn/register-options', async (req, res) => {
  const options = await fido2.attestationOptions();
  options.user = {
    id: Buffer.from(req.user.id),
    name: req.user.email,
    displayName: req.user.name
  };
  options.authenticatorSelection = {
    authenticatorAttachment: 'cross-platform', // external keys
    userVerification: 'preferred',
    residentKey: 'preferred'
  };
  
  req.session.webauthnChallenge = options.challenge;
  res.json(options);
});

app.post('/mfa/webauthn/register', async (req, res) => {
  const result = await fido2.attestationResult(
    req.body,
    { challenge: req.session.webauthnChallenge, origin: 'https://yourapp.com', factor: 'second' }
  );
  
  await db.mfaDevices.create({
    userId: req.user.id,
    type: 'webauthn',
    name: req.body.deviceName,
    credentialId: result.authnrData.get('credId'),
    publicKey: result.authnrData.get('credentialPublicKeyPem'),
    counter: result.authnrData.get('counter')
  });
  
  res.json({ success: true });
});

SMS OTP: Legacy Support Only

SMS one-time passwords should be offered only for legacy compatibility and for users who cannot use app-based or hardware MFA. SIM-swapping attacks undermine SMS security. If you must use SMS:

  • 6-digit codes, 5-minute expiry, single-use.
  • Rate limit: 3 OTP requests per phone number per 10 minutes.
  • Phone number verification via a separate flow before enabling SMS MFA.
  • Notify by email when SMS MFA is added or used from a new location.

Passkeys: MFA That Replaced Passwords in 2026

Passkeys (FIDO2 discoverable credentials) are the most significant shift in authentication since passwords. A passkey is a cryptographic key pair stored on the user's device, protected by biometrics or PIN. The user authenticates with a fingerprint or face scan — no password, no separate MFA code.

Passkeys are simultaneously: - Phishing-proof (cryptographically bound to origin) - Phishable-password-free (no password to steal or brute-force) - Convenient (one gesture replaces password + MFA) - Synced across devices (iCloud Keychain, Google Password Manager, 1Password)

javascript
// Passkey registration
app.post('/auth/passkey/register-options', (req, res) => {
  const options = generateRegistrationOptions({
    rpName: 'YourApp',
    rpID: 'yourapp.com',
    userID: req.user.id,
    userName: req.user.email,
    attestationType: 'none',
    authenticatorSelection: {
      residentKey: 'required',        // creates discoverable credential
      userVerification: 'required'    // biometric/PIN required
    },
    supportedAlgorithmIDs: [-7, -257] // ES256, RS256
  });
  req.session.passkeyChallenge = options.challenge;
  res.json(options);
});

// Passkey authentication — no username required
app.post('/auth/passkey/login-options', (req, res) => {
  const options = generateAuthenticationOptions({
    rpID: 'yourapp.com',
    userVerification: 'required'
    // No allowCredentials — browser presents all matching passkeys
  });
  req.session.passkeyChallenge = options.challenge;
  res.json(options);
});

ZeriFlow checks that your login pages and authentication flows are served over secure connections and with the headers that protect stored credentials — Strict-Transport-Security and Content-Security-Policy are particularly critical for passkey and MFA flows.

Deployment Strategy: Achieving High Enrollment

The best MFA implementation is worthless if users do not enroll. Strategies for high adoption:

For consumer apps: 1. Show a security score or badge for accounts without MFA. 2. Offer incentives (extended free trial, storage bonus) for enabling MFA. 3. Implement stepped security: certain actions (changing email, withdrawing funds) require MFA even if not globally enabled. 4. Never make MFA opt-out by burying the setting — surface it prominently after signup.

For B2B/enterprise apps: 1. Enforce MFA at the organization level — admins require it for all members. 2. Set a grace period (7-14 days) for existing users, then block access. 3. Exempt service accounts explicitly; require hardware keys for admin roles.

javascript
// Enforcement middleware
async function enforceMFA(req, res, next) {
  const user = req.user;
  if (!user) return next();

  const org = await db.orgs.findById(user.orgId);
  if (!org?.mfaRequired) return next(); // MFA not required for this org

  if (!user.mfaEnrolled) {
    return res.status(403).json({
      error: 'mfa_required',
      message: 'Your organization requires MFA. Please set it up to continue.',
      setupUrl: '/settings/security/mfa'
    });
  }

  if (!req.session.mfaVerifiedAt || 
      Date.now() - req.session.mfaVerifiedAt > 12 * 3600 * 1000) {
    return res.status(401).json({
      error: 'mfa_challenge_required',
      challengeUrl: '/auth/mfa/challenge'
    });
  }

  next();
}

FAQ

### Q: What is the difference between MFA and passkeys? A: Traditional MFA adds a second factor on top of a password (know + have). Passkeys replace both the password and the second factor with a single cryptographic key protected by biometrics. Passkeys are simpler for users and more secure, as there is no password to phish and the key is origin-bound.

### Q: Should I remove SMS MFA from my application? A: Remove it as the default, but offer it as a fallback for accessibility. Some users do not have smartphones capable of running authenticator apps. Require users to acknowledge the reduced security of SMS. For high-security applications (banking, admin access), prohibit SMS MFA entirely.

### Q: How do I handle MFA recovery at scale? A: Pre-generate 10 single-use backup codes at enrollment. Send a secure recovery link via verified email as a second recovery option. Do not allow support staff to bypass MFA without verified identity — this is a common social engineering attack vector. Consider trusted device lists for low-risk contexts.

### Q: Are biometrics safe to use for MFA? A: Biometrics stored on-device (TouchID, FaceID, Windows Hello) are safe — the biometric never leaves the device. Cloud-stored biometrics raise privacy concerns. In FIDO2/WebAuthn, the biometric is used locally to unlock the cryptographic key; the biometric itself is never sent to your server.

### Q: Should I enforce MFA immediately or give a grace period? A: Give existing users a grace period of 7-14 days with clear communication about the change and why it matters. Send reminders at 7 days, 3 days, and 1 day before enforcement. Enforce immediately for all new users. For admin accounts, enforce immediately with no grace period.


Conclusion

Multi-factor authentication is the most effective single security control you can deploy. Start with TOTP app-based MFA as your baseline. Add hardware key support for high-privilege users. Adopt passkeys for new user flows in 2026 — they deliver better security and better usability simultaneously. Enforce MFA with an organizational policy, not just an option, and back it up with technical controls that verify MFA status on every sensitive operation.

Run a free ZeriFlow scan → — no credit card required.

Ready to check your site?

Run a free security scan in 30 seconds.

Related articles

Keep reading