Skip to Content
DocumentationGetting StartedStep-up AuthStep 4: Handle MFA Response

Step 4: Handle MFA Response

⏱ 5 min

Process the MFA verification result and implement your security logic.


MFA Response Structure

interface MfaResult { success: boolean; payload: [{ verified: boolean; method: 'totp' | 'email' | 'hardware_key'; verifiedAt: string; // ISO timestamp }]; }

Basic Handling

const mfaResult = await transcodes.openAuthMfaModal(); if (mfaResult.success) { const { method, verifiedAt } = mfaResult.payload[0]; console.log(`Verified via ${method} at ${verifiedAt}`); // Proceed with protected action await performSensitiveAction(); } else { // User cancelled or verification failed console.log('MFA verification not completed'); }

MFA Verification Token

After successful MFA, you can get a verification token to send to your server:

const mfaResult = await transcodes.openAuthMfaModal(); if (mfaResult.success) { // Get the MFA verification token const mfaToken = await transcodes.token.getMfaToken(); // Send to your server with the protected request const response = await fetch('/api/admin/settings', { method: 'POST', headers: { 'Authorization': `Bearer ${await transcodes.token.getAccessToken()}`, 'X-MFA-Token': mfaToken, }, body: JSON.stringify({ setting: 'value' }), }); }

Server-Side Verification

On your server, verify both the access token and MFA token:

// Node.js / Express app.post('/api/admin/settings', async (req, res) => { // 1. Verify access token (user is logged in) const accessToken = req.headers.authorization?.split(' ')[1]; const user = await verifyAccessToken(accessToken); if (!user) { return res.status(401).json({ error: 'Unauthorized' }); } // 2. Verify MFA token (user completed MFA) const mfaToken = req.headers['x-mfa-token']; const mfaValid = await verifyMfaToken(mfaToken); if (!mfaValid) { return res.status(403).json({ error: 'MFA verification required' }); } // 3. Proceed with sensitive action await updateSettings(req.body); res.json({ success: true }); });

MFA Session Caching

To avoid requiring MFA on every action, you can cache the MFA verification:

class MfaManager { constructor() { this.mfaVerifiedAt = null; this.mfaValidDuration = 15 * 60 * 1000; // 15 minutes } async requireMfa() { // Check if MFA was recently verified if (this.isMfaValid()) { return true; } // Prompt for MFA const result = await transcodes.openAuthMfaModal(); if (result.success) { this.mfaVerifiedAt = Date.now(); return true; } return false; } isMfaValid() { if (!this.mfaVerifiedAt) return false; const elapsed = Date.now() - this.mfaVerifiedAt; return elapsed < this.mfaValidDuration; } clearMfa() { this.mfaVerifiedAt = null; } } // Usage const mfaManager = new MfaManager(); async function accessAdminPanel() { if (await mfaManager.requireMfa()) { // MFA valid - proceed showAdminPanel(); } }

Best Practices

Security Recommendations:

  1. Always verify MFA server-side - Don’t trust client-side MFA alone
  2. Set reasonable MFA session duration - 15-30 minutes is typical
  3. Clear MFA on logout - Reset MFA cache when user logs out
  4. Log MFA events - Track when MFA is used for audit purposes

Handle User Without MFA

If a user hasn’t set up MFA yet:

const mfaResult = await transcodes.openAuthMfaModal(); if (!mfaResult.success) { // Check if user has MFA set up const hasMfa = await transcodes.user.hasMfaEnabled(); if (!hasMfa) { // Redirect to MFA setup alert('Please set up MFA first'); await transcodes.openAuthModal(); // Opens console panel for MFA setup } }

Congratulations!

πŸŽ‰ You’ve successfully integrated Step-up MFA into your application!

No server-side verification is needed for MFA β€” the verification is handled entirely by Transcodes.

Last updated on