# TA-ATS Login Architecture & Flow Chart

This document explains how the credentials verification and multi-factor authentication (MFA) logic is distributed across the different services in the TA-ATS ecosystem, with a focus on the Model Context Protocol (MCP) authentication integration.

---

## 🏗️ Architecture Overview

The TA-ATS system uses a 4-tier modular architecture:

```
[ Browser / Frontend ] (Next.js - Port 3000)
         │
         ▼ (Calls /api/*)
  [ Gateway ] (FastAPI - Port 8000)
         │
         ▼ (Proxies to)
  [ Django Backend ] (Port 8002) ───[ ats_main DB ] (PostgreSQL - User Profiles)
         │
         ▼ (MCP Client Handshake via HTTP/Stdio)
   [ MCP Service ] (FastMCP - Port 9000) ───[ ats_mcp_db ] (PostgreSQL - Credentials & MFA)
```

1. **Frontend (Next.js - Port 3000):** Renders the user interface. It is responsible for gathering credentials, presenting the MFA screen (OTP input or QR code scan), and managing the session.
2. **Gateway (FastAPI - Port 8000):** Acts as the single entry point. It handles rate-limiting and redirects all `/api/*` requests directly to the Django backend.
3. **Backend (Django - Port 8002):** Holds the main application logic, user roles, profile information, and tables in the **`ats_main`** database. It delegates credential validation and MFA cryptography to the MCP service.
4. **MCP Service (FastMCP - Port 9000):** A separate Microservice that connects directly to the secure **`ats_mcp_db`** database. It manages passwords, OTPs, and TOTP secrets and exposes tools like `verify_login`, `sync_user`, `send_email_otp`, and `verify_mfa_code`.

---

## 🔑 Login Flow Step-by-Step

### Phase 1: Authentication (Password Verification)
1. The user enters their **Email** and **Password** on the Frontend (`http://localhost:3000/login`).
2. The Frontend sends a request to the Gateway, which forwards it to the Django Backend (`/api/v1/auth/login/`).
3. Django's Custom Authentication Backend ([MCPAuthBackend](file:///c:/Users/Kunal%20Verma/Desktop/Python/TA-ATS/backend/apps/authentication/backends.py)) intercepts the request and calls the MCP service tool **`verify_login(email, password)`** over HTTP/Stdio.
4. The **MCP Service** queries the `mcp_users` table in `ats_mcp_db`:
   - It retrieves the hashed password (`pbkdf2_sha256` format) for the email.
   - It hashes the input password and checks for a match.
   - It returns `{"verified": true, "role": "..."}` or `{"verified": false}`.
5. If verified, Django looks up the user in its local `ats_main` database. If it's a new user authenticated via MCP, Django automatically mirrors / creates the local user profile.

### Phase 2: MFA Verification (Two-Factor Challenge)
1. Django checks the central MFA policy configured on the MCP Service (`get_mfa_policy`):
   - **No MFA:** Django issues the JWT access & refresh tokens immediately.
   - **Email OTP:** Django requests the MCP Service to send an OTP via email (`send_email_otp`). The MCP generates the OTP, sends the email, and returns it to Django. Django stores this OTP locally inside the `OTPRecord` table and prompts the user on the UI.
   - **Authenticator (TOTP):** Django checks if the user has already enrolled in Authenticator MFA.
     - *If Enrolled:* Django returns `mfa_required` to the frontend.
     - *If Not Enrolled:* Django allows the user to log in but directs the frontend to open the QR Code/TOTP Setup flow (`needs_totp_setup=true`) on the dashboard.
2. The user enters the 6-digit MFA code on the frontend.
3. The frontend submits the code to `/api/v1/auth/verify-mfa/`.
4. Django validates the code:
   - For **Email OTP**: Django matches the input with the local `OTPRecord`.
   - For **TOTP (Google Authenticator)**: Django forwards the code and secret to MCP's **`verify_mfa_code(secret, code)`** tool.
5. If validation succeeds, Django marks the user's session as verified, updates `last_login`, and returns the final JWT access and refresh tokens.

---

## 📊 Detailed Flow Chart

```mermaid
sequenceDiagram
    autonumber
    actor User as User Browser
    participant FE as Frontend (Next.js)
    participant GW as Gateway (FastAPI)
    participant Django as Backend (Django)
    participant MCP as MCP Service (FastMCP)
    database LocalDB as ats_main (Local DB)
    database McpDB as ats_mcp_db (MCP DB)

    Note over User, McpDB: PHASE 1: CREDENTIALS AUTHENTICATION
    User->>FE: Enters Email & Password
    FE->>GW: POST /api/v1/auth/login/
    GW->>Django: Proxy request to Django
    Django->>MCP: call_tool: verify_login(email, password)
    MCP->>McpDB: Query credentials from `mcp_users`
    McpDB-->>MCP: Return pbkdf2_sha256 password hash & role
    Note over MCP: Verify password using pbkdf2_sha256
    MCP-->>Django: Return {"verified": true, "role": "ADMIN"}
    
    alt User profile doesn't exist locally
        Django->>LocalDB: Create mirrored User profile
    end

    Note over User, McpDB: PHASE 2: MFA CENTRAL POLICY ENFORCEMENT
    Django->>MCP: call_tool: get_mfa_policy()
    MCP-->>Django: Return {"method": "email"} (or "totp" / "none")

    alt Policy: Email OTP
        Django->>MCP: call_tool: send_email_otp(email)
        MCP-->>User: Sends email with 6-digit OTP
        MCP-->>Django: Return {"otp": "123456", "sent": true}
        Django->>LocalDB: Save "123456" in OTPRecord
        Django-->>FE: Return {"mfa_required": true, "method": "email"}
        FE-->>User: Prompt for Email OTP Code
        User->>FE: Enters code "123456"
        FE->>GW: POST /api/v1/auth/verify-mfa/ (code="123456")
        GW->>Django: Proxy request to Django
        Django->>LocalDB: Validate code matches OTPRecord
        LocalDB-->>Django: Valid!
    else Policy: Authenticator App (TOTP)
        alt User already enrolled
            Django-->>FE: Return {"mfa_required": true, "method": "totp"}
            FE-->>User: Prompt for Authenticator Code
            User->>FE: Enters 6-digit code
            FE->>GW: POST /api/v1/auth/verify-mfa/ (code)
            GW->>Django: Proxy request to Django
            Django->>MCP: call_tool: verify_mfa_code(totp_secret, code)
            MCP-->>Django: Return {"verified": true}
        else User NOT enrolled
            Django-->>FE: Return login tokens + {"needs_totp_setup": true}
            FE->>User: Opens Dashboard setup, requests QR code
            FE->>Django: GET /api/v1/auth/mfa/setup/
            Django->>MCP: call_tool: generate_mfa_secret()
            MCP-->>Django: Return new TOTP Secret
            Django->>MCP: call_tool: get_provisioning_uri(secret, email)
            MCP-->>Django: Return otpauth:// URI
            Django->>Django: Convert URI to Base64 QR Image
            Django-->>FE: Return QR Code Image + TOTP Secret
            FE->>User: Display QR code to scan in Google Authenticator
            User->>FE: Input verification code from Authenticator
            FE->>Django: POST /api/v1/auth/mfa/enable/ (code)
            Django->>MCP: call_tool: verify_mfa_code(secret, code)
            MCP-->>Django: Return {"verified": true}
            Django->>LocalDB: Save totp_secret and set mfa_enabled = true
        end
    end

    Note over User, McpDB: PHASE 3: JWT ISSUANCE (SUCCESS)
    Django->>Django: Generate Access & Refresh JWTs
    Django-->>GW: Return JWT tokens
    GW-->>FE: Return JWT tokens
    FE->>User: Redirect to Dashboard (/dashboard)
```
