# Frontend 2FA Integration Guide

## 🚀 New 2FA Flow Overview

Your frontend now has a clean 2-step 2FA flow where users can choose between:
1. **Authenticator App** (traditional 2FA)
2. **Email Code** (fallback option)

## 📋 API Endpoints

### **1. Initial Login**
```
POST /api/authenticate
```

**Request:**
```json
{
  "email": "user@example.com",
  "password": "password123"
}
```

**Response (if 2FA enabled):**
```json
{
  "message": "Two-factor authentication required.",
  "requires_2fa": true,
  "user_id": 123,
  "available_methods": {
    "authenticator": "Use your authenticator app code",
    "email": "Request a code via email"
  },
  "has_email_fallback": true
}
```

### **2. Select 2FA Method**
```
POST /api/2fa/select-method
```

**Request:**
```json
{
  "user_id": 123,
  "method": "email"  // or "authenticator"
}
```

**Response (Email Method):**
```json
{
  "success": true,
  "message": "Verification code sent to your email",
  "method": "email",
  "expires_in": 600,
  "user_email": "user@example.com"
}
```

**Response (Authenticator Method):**
```json
{
  "success": true,
  "message": "Ready for authenticator app verification",
  "method": "authenticator"
}
```

### **3. Verify 2FA Code**
```
POST /api/2fa/verify-code
```

**Request:**
```json
{
  "user_id": 123,
  "code": "123456",
  "method": "email"  // or "authenticator", "recovery"
}
```

**Response (Success):**
```json
{
  "success": true,
  "message": "2FA verification successful",
  "method_used": "email",
  "user_id": 123
}
```

### **4. Complete Authentication**
```
POST /api/2fa/complete-auth
```

**Request:**
```json
{
  "user_id": 123,
  "method_used": "email"
}
```

**Response:**
```json
{
  "access_token": "token_here",
  "user": { ... },
  "requires_2fa": false,
  "method_used": "email"
}
```

## 🎯 Frontend Implementation

### **JavaScript Class:**

```javascript
class TwoFactorAuth {
  constructor() {
    this.userId = null;
    this.selectedMethod = null;
  }

  // Step 1: Initial login
  async login(email, password) {
    try {
      const response = await fetch('/api/authenticate', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password })
      });

      const data = await response.json();
      
      if (data.requires_2fa) {
        this.userId = data.user_id;
        return {
          requires2FA: true,
          availableMethods: data.available_methods,
          userId: data.user_id
        };
      }
      
      return data; // No 2FA required
    } catch (error) {
      console.error('Login failed:', error);
      throw error;
    }
  }

  // Step 2: Select method
  async selectMethod(method) {
    try {
      const response = await fetch('/api/2fa/select-method', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          user_id: this.userId,
          method: method
        })
      });

      const data = await response.json();
      
      if (!data.success) {
        throw new Error(data.message);
      }
      
      this.selectedMethod = method;
      return data;
    } catch (error) {
      console.error('Method selection failed:', error);
      throw error;
    }
  }

  // Step 3: Verify code
  async verifyCode(code) {
    try {
      const response = await fetch('/api/2fa/verify-code', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          user_id: this.userId,
          code: code,
          method: this.selectedMethod
        })
      });

      const data = await response.json();
      
      if (!data.success) {
        throw new Error(data.message);
      }
      
      return data;
    } catch (error) {
      console.error('Code verification failed:', error);
      throw error;
    }
  }

  // Step 4: Complete authentication
  async completeAuth() {
    try {
      const response = await fetch('/api/2fa/complete-auth', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          user_id: this.userId,
          method_used: this.selectedMethod
        })
      });

      const data = await response.json();
      
      if (!response.ok) {
        throw new Error(data.message || 'Authentication failed');
      }
      
      return data;
    } catch (error) {
      console.error('Authentication completion failed:', error);
      throw error;
    }
  }

  // Complete flow
  async authenticate(email, password, method, code) {
    try {
      // Step 1: Login
      const loginResult = await this.login(email, password);
      
      if (!loginResult.requires2FA) {
        return loginResult; // No 2FA needed
      }

      // Step 2: Select method
      await this.selectMethod(method);

      // Step 3: Verify code
      await this.verifyCode(code);

      // Step 4: Complete auth
      return await this.completeAuth();
    } catch (error) {
      console.error('Authentication failed:', error);
      throw error;
    }
  }
}
```

### **React Component Example:**

```javascript
import React, { useState } from 'react';

function TwoFactorAuth({ email, password, onSuccess, onBack }) {
  const [step, setStep] = useState('method-selection'); // method-selection, code-input, loading
  const [selectedMethod, setSelectedMethod] = useState('');
  const [code, setCode] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [timeLeft, setTimeLeft] = useState(600);
  const [userId, setUserId] = useState(null);
  const [availableMethods, setAvailableMethods] = useState({});

  const twoFactor = new TwoFactorAuth();

  const handleMethodSelection = async (method) => {
    setLoading(true);
    setError('');
    
    try {
      const result = await twoFactor.selectMethod(method);
      setSelectedMethod(method);
      setStep('code-input');
      
      if (method === 'email') {
        startCountdown();
      }
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  const handleCodeVerification = async () => {
    setLoading(true);
    setError('');
    
    try {
      await twoFactor.verifyCode(code);
      const authResult = await twoFactor.completeAuth();
      onSuccess(authResult);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  const startCountdown = () => {
    const timer = setInterval(() => {
      setTimeLeft((prev) => {
        if (prev <= 1) {
          clearInterval(timer);
          return 600;
        }
        return prev - 1;
      });
    }, 1000);
  };

  const formatTime = (seconds) => {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  };

  return (
    <div className="two-factor-auth">
      {step === 'method-selection' && (
        <div className="method-selection">
          <h3>Choose Verification Method</h3>
          <p>How would you like to verify your identity?</p>
          
          {availableMethods.authenticator && (
            <button 
              onClick={() => handleMethodSelection('authenticator')}
              disabled={loading}
              className="method-button"
            >
              📱 Use Authenticator App
            </button>
          )}
          
          {availableMethods.email && (
            <button 
              onClick={() => handleMethodSelection('email')}
              disabled={loading}
              className="method-button"
            >
              📧 Send Code to Email
            </button>
          )}
          
          <button onClick={onBack} className="btn-back">
            ← Back
          </button>
        </div>
      )}

      {step === 'code-input' && (
        <div className="code-input">
          <h3>
            {selectedMethod === 'authenticator' ? 'Enter Authenticator Code' : 'Enter Email Code'}
          </h3>
          
          {selectedMethod === 'email' && (
            <div className="email-info">
              <p>Code sent to: {email}</p>
              <div className="timer">
                Expires in: {formatTime(timeLeft)}
              </div>
            </div>
          )}
          
          <input
            type="text"
            value={code}
            onChange={(e) => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
            placeholder="123456"
            maxLength="6"
            className="code-input-field"
          />
          
          <button 
            onClick={handleCodeVerification}
            disabled={loading || code.length !== 6}
            className="btn-primary"
          >
            {loading ? 'Verifying...' : 'Verify'}
          </button>
          
          {selectedMethod === 'email' && (
            <button 
              onClick={() => handleMethodSelection('email')}
              disabled={loading}
              className="btn-secondary"
            >
              Resend Code
            </button>
          )}
          
          <button onClick={() => setStep('method-selection')} className="btn-back">
            ← Back to Methods
          </button>
        </div>
      )}

      {error && <div className="error-message">{error}</div>}
      
      {loading && <div className="loading">Processing...</div>}
    </div>
  );
}
```

### **Complete Login Flow Example:**

```javascript
// Main login component
function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [show2FA, setShow2FA] = useState(false);
  const [loginData, setLoginData] = useState(null);

  const handleLogin = async (e) => {
    e.preventDefault();
    
    try {
      const twoFactor = new TwoFactorAuth();
      const result = await twoFactor.login(email, password);
      
      if (result.requires2FA) {
        setShow2FA(true);
        setLoginData(result);
      } else {
        // Direct login success
        onLoginSuccess(result);
      }
    } catch (error) {
      setError(error.message);
    }
  };

  const handle2FASuccess = (authResult) => {
    setShow2FA(false);
    onLoginSuccess(authResult);
  };

  return (
    <div>
      {!show2FA ? (
        <form onSubmit={handleLogin}>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            placeholder="Email"
            required
          />
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            placeholder="Password"
            required
          />
          <button type="submit">Login</button>
        </form>
      ) : (
        <TwoFactorAuth
          email={email}
          password={password}
          onSuccess={handle2FASuccess}
          onBack={() => setShow2FA(false)}
        />
      )}
    </div>
  );
}
```

## 🎨 CSS Styling

```css
.two-factor-auth {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.method-selection {
  text-align: center;
}

.method-button {
  display: block;
  width: 100%;
  padding: 15px;
  margin: 10px 0;
  border: 2px solid #ddd;
  background: #f8f9fa;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
  transition: all 0.3s;
}

.method-button:hover {
  border-color: #007bff;
  background: #007bff;
  color: white;
}

.code-input-field {
  width: 100%;
  padding: 15px;
  font-size: 24px;
  text-align: center;
  letter-spacing: 8px;
  border: 2px solid #ddd;
  border-radius: 8px;
  margin: 20px 0;
}

.email-info {
  background: #e3f2fd;
  padding: 15px;
  border-radius: 8px;
  margin: 15px 0;
}

.timer {
  color: #666;
  font-size: 14px;
  margin-top: 10px;
}

.btn-primary {
  background: #007bff;
  color: white;
  padding: 12px 24px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}

.btn-secondary {
  background: #6c757d;
  color: white;
  padding: 12px 24px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  margin: 5px;
}

.btn-back {
  background: none;
  border: none;
  color: #007bff;
  cursor: pointer;
  padding: 10px;
}

.error-message {
  background: #f8d7da;
  color: #721c24;
  padding: 12px;
  border-radius: 6px;
  margin: 10px 0;
}

.loading {
  text-align: center;
  color: #666;
  padding: 20px;
}
```

## 🔄 Complete Flow Summary

1. **User enters email/password** → `/api/authenticate`
2. **Backend returns 2FA options** → User chooses method
3. **Method selection** → `/api/2fa/select-method`
4. **Code verification** → `/api/2fa/verify-code`
5. **Complete authentication** → `/api/2fa/complete-auth`

## 🎯 Benefits

- **Clear user choice** between methods
- **Separate API calls** for better error handling
- **Flexible flow** supports future methods
- **Clean separation** of concerns
- **Better UX** with method selection UI

Your frontend now has a clean, flexible 2FA system that gives users clear choices! 🚀
