Multi-Factor Authentication

Add an extra layer of security to your application with MFA. Protect user accounts with time-based one-time passwords (TOTP).

What is Multi-Factor Authentication?

Multi-Factor Authentication (MFA) adds an additional layer of security beyond just a username and password. It requires users to provide two or more verification factors to gain access to their account.

Authentication Factors

  • Something you know: Password, PIN, security question
  • Something you have: Phone, hardware token, authenticator app
  • Something you are: Fingerprint, facial recognition, biometrics

OAuth42 implements MFA using Time-Based One-Time Passwords (TOTP), which fall under the "something you have" category. Users generate time-sensitive codes using authenticator apps on their mobile devices.

Why Use MFA?

Protection Against Common Attacks

  • • Prevents credential stuffing attacks
  • • Blocks phishing attempts
  • • Mitigates password breaches
  • • Stops brute force attacks

Compliance & Trust

  • • Meets regulatory requirements
  • • Industry standard security
  • • Builds user confidence
  • • Reduces liability

TOTP (Time-Based One-Time Password)

OAuth42 uses TOTP as defined in RFC 6238. TOTP generates a 6-digit code that changes every 30 seconds, providing time-sensitive verification.

How TOTP Works

  1. A shared secret is generated and stored securely on the server
  2. The secret is shared with the user's authenticator app (via QR code or manual entry)
  3. Both server and app use the same algorithm to generate codes based on the current time
  4. User enters the code from their app to verify they have the device
  5. Server validates the code matches what it expects for the current time window

Supported Authenticator Apps

OAuth42 works with any RFC 6238 compliant authenticator app:

  • • Google Authenticator
  • • Microsoft Authenticator
  • • Authy
  • • 1Password
  • • Bitwarden
  • • Any TOTP-compatible app

MFA Setup Flow

Enable MFA for a user account through the following steps:

1

Initiate MFA Setup

Call the MFA setup endpoint to generate a new TOTP secret for the user.

POST /api/mfa/setup
Authorization: Bearer ACCESS_TOKEN

Response:
{
  "secret": "JBSWY3DPEHPK3PXP",
  "qrCode": "data:image/png;base64,iVBORw0KG...",
  "backupCodes": [
    "1234-5678",
    "9012-3456",
    "5678-9012"
  ]
}
2

Display QR Code

Show the QR code to the user so they can scan it with their authenticator app. Also provide the secret key for manual entry as a fallback.

3

Verify TOTP Code

User enters a code from their authenticator app to confirm setup.

POST /api/mfa/verify-setup
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "code": "123456"
}

Response:
{
  "success": true,
  "enabled": true
}
4

Save Backup Codes

Instruct users to save their backup codes in a secure location. These codes can be used to access their account if they lose their authenticator device.

Authentication Flow with MFA

When MFA is enabled, the authentication flow requires an additional verification step:

# Step 1: Normal OAuth2 authentication
POST /oauth/authorize
  client_id=YOUR_CLIENT_ID
  redirect_uri=YOUR_REDIRECT_URI
  scope=openid profile email
  state=RANDOM_STATE
  code_challenge=CODE_CHALLENGE
  code_challenge_method=S256

# Step 2: User enters username/password
# If MFA is enabled, server responds with:
{
  "mfa_required": true,
  "mfa_token": "temp_token_abc123"
}

# Step 3: User enters TOTP code
POST /oauth/authorize/mfa
Content-Type: application/json

{
  "mfa_token": "temp_token_abc123",
  "code": "123456"
}

# Step 4: On success, complete OAuth flow
Response: 302 Redirect
Location: YOUR_REDIRECT_URI?code=AUTH_CODE&state=RANDOM_STATE

Backup Codes

Backup codes provide account recovery when users lose access to their authenticator device. Each code can only be used once.

Using Backup Codes

POST /oauth/authorize/mfa
Content-Type: application/json

{
  "mfa_token": "temp_token_abc123",
  "backup_code": "1234-5678"
}

Response:
{
  "success": true,
  "remaining_codes": 2
}

⚠️ Important

  • • Backup codes are single-use only
  • • Users should store codes securely (password manager, printed copy)
  • • Warn users when they have few backup codes remaining
  • • Allow users to generate new backup codes (requires current authentication)

Account Recovery

If a user loses both their authenticator device and backup codes, they need to go through a recovery process.

Recovery Options

Option 1: Email-Based Recovery

User requests MFA reset via email. After verifying identity, a time-limited recovery link is sent to disable MFA temporarily.

Option 2: Admin Reset

For enterprise accounts, administrators can disable MFA after verifying user identity through your organization's verification process.

Option 3: Support Ticket

Users contact support with identity verification documents. Support staff can disable MFA after thorough verification.

Implementation Example

TypeScript/React Example

import { useState } from 'react';
import { OAuth42Client } from '@oauth42/sdk';

const client = new OAuth42Client({
  clientId: 'your_client_id',
  redirectUri: 'http://localhost:3000/callback'
});

// Setup MFA
async function setupMFA(accessToken: string) {
  const response = await fetch('/api/mfa/setup', {
    headers: {
      'Authorization': `Bearer ${accessToken}`
    }
  });

  const { secret, qrCode, backupCodes } = await response.json();

  // Display QR code to user
  return { secret, qrCode, backupCodes };
}

// Verify MFA setup
async function verifyMFASetup(accessToken: string, code: string) {
  const response = await fetch('/api/mfa/verify-setup', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ code })
  });

  const result = await response.json();
  return result.success;
}

// Login with MFA
async function loginWithMFA(username: string, password: string) {
  // Step 1: Initial authentication
  const authResponse = await client.authenticate(username, password);

  if (authResponse.mfa_required) {
    // Step 2: Prompt for MFA code
    const mfaCode = await promptUserForMFACode();

    // Step 3: Complete MFA challenge
    const tokens = await client.completeMFA(
      authResponse.mfa_token,
      mfaCode
    );

    return tokens;
  }

  return authResponse.tokens;
}

Best Practices

Require MFA for Sensitive Operations

Even if a user is authenticated, require MFA verification for sensitive actions like:

  • • Changing password or email
  • • Disabling MFA
  • • Viewing/regenerating API keys
  • • Deleting account

Grace Period for New MFA

Allow a short grace period (e.g., 5 minutes) after setup before requiring MFA. This lets users add backup authentication methods without getting locked out.

Remember Trusted Devices

Optionally allow users to mark devices as "trusted" and skip MFA for 30 days. Store a secure cookie to identify the trusted device.

Rate Limit MFA Attempts

Implement rate limiting on MFA verification endpoints to prevent brute force attacks. Lock accounts temporarily after multiple failed attempts.

Clear User Communication

Provide clear instructions during MFA setup and use. Include visual guides showing how to scan QR codes and where to find codes in authenticator apps.

Audit MFA Events

Log all MFA-related events for security monitoring:

  • • MFA enabled/disabled
  • • Failed verification attempts
  • • Backup code usage
  • • Recovery requests

Next Steps