Implementing Multi-Factor Authentication in Next.js 14
auth

Implementing Multi-Factor Authentication in Next.js 14

By Marcus Weber18 min read25 January 20244,231 views
  <h2>Why Multi-Factor Authentication?</h2>
  <p>Passwords alone are no longer sufficient. With data breaches exposing billions of credentials, MFA has become essential for protecting user accounts. For EU applications, MFA is often required for GDPR compliance when handling sensitive data.</p>
  
  <h2>Types of MFA</h2>
  <p>There are three main types of authentication factors:</p>
  <ul>
    <li><strong>Something you know:</strong> Password, PIN</li>
    <li><strong>Something you have:</strong> Phone, authenticator app, hardware key</li>
    <li><strong>Something you are:</strong> Fingerprint, face recognition</li>
  </ul>
  
  <h2>Implementing TOTP (Authenticator Apps)</h2>
  <p>Time-based One-Time Passwords (TOTP) are the most popular MFA method. They work with apps like Google Authenticator, Authy, and 1Password.</p>
  
  <pre><code>// Install required package

npm install otplib qrcode

// Generate secret and QR code import { authenticator } from 'otplib'; import QRCode from 'qrcode';

export async function generateMFASecret(userId: string, email: string) { const secret = authenticator.generateSecret(); const otpauth = authenticator.keyuri(email, 'YourApp', secret); const qrCode = await QRCode.toDataURL(otpauth);

// Store secret in database await User.findByIdAndUpdate(userId, { mfaSecret: secret });

return { secret, qrCode }; }

  <h2>Verifying TOTP Codes</h2>
  <pre><code>import { authenticator } from 'otplib';

export function verifyMFACode(secret: string, token: string): boolean { return authenticator.verify({ token, secret }); }

// In your login route const isValid = verifyMFACode(user.mfaSecret, req.body.mfaCode); if (!isValid) { return res.status(401).json({ error: 'Invalid MFA code' }); }

  <h2>SMS-Based MFA</h2>
  <p>SMS is convenient but less secure than TOTP. Use it as a fallback option.</p>
  
  <pre><code>// Using Twilio for SMS

import twilio from 'twilio';

const client = twilio(accountSid, authToken);

export async function sendMFACode(phoneNumber: string) { const code = Math.floor(100000 + Math.random() * 900000).toString();

await client.messages.create({ body: Your verification code is: ${code}, from: '+1234567890', to: phoneNumber, });

// Store code in Redis with 5-minute expiration await redis.setex(mfa:${phoneNumber}, 300, code);

return code; }

  <h2>Recovery Codes</h2>
  <p>Always provide backup recovery codes in case users lose access to their MFA device.</p>
  
  <pre><code>export function generateRecoveryCodes(count: number = 10): string[] {

return Array.from({ length: count }, () => crypto.randomBytes(4).toString('hex').toUpperCase() ); }

// Store hashed recovery codes const codes = generateRecoveryCodes(); const hashedCodes = codes.map(code => bcrypt.hashSync(code, 10)); await User.findByIdAndUpdate(userId, { recoveryCodes: hashedCodes });

  <h2>User Experience Considerations</h2>
  <p>MFA should be secure without being frustrating:</p>
  <ul>
    <li>Make MFA optional for low-risk accounts</li>
    <li>Remember devices for 30 days</li>
    <li>Provide clear setup instructions</li>
    <li>Offer multiple MFA methods</li>
    <li>Show recovery codes during setup</li>
  </ul>
  
  <h2>Testing MFA</h2>
  <p>Test all MFA flows thoroughly:</p>
  <ul>
    <li>Setup flow (QR code generation, code verification)</li>
    <li>Login flow (prompt for MFA, verify code)</li>
    <li>Recovery flow (use recovery codes)</li>
    <li>Device remembering (skip MFA on trusted devices)</li>
    <li>Error handling (invalid codes, expired codes)</li>
  </ul>
  
  <h2>Conclusion</h2>
  <p>MFA significantly improves account security. By implementing TOTP with proper backup options and a smooth UX, you can protect your users while maintaining a good experience. For EU applications, MFA is becoming a requirement rather than a nice-to-have.</p>
About the Author
Marcus Weber
Marcus Weber

Lead QA Engineer

Built testing frameworks used by 50+ companies, 12+ years in QA

QA Engineer and testing advocate. Built testing frameworks for Fortune 500 companies. Passionate about making testing accessible and effective for all developers.

Expertise:
JestPlaywrightCypressTesting StrategyCI/CDTest Automation

Get notified of updates

Subscribe to receive an email when this article is updated with new information.

We'll only email you about updates to this specific article. Unsubscribe anytime.
Share this article
Tags
mfa2famulti-factor-authenticationtotpsecuritynextjsauthentication

Related Articles

View all Auth