Team: Transcende_me_if_you_can
- About / Project Overview
- Resources & References
- Token/2FA Authentication Brief & Resources
- Structure & Workflow Diagrams
- Test Commands
- Key Concepts Learned
- Skills Developed
Ft_transcendence is a full-stack web application project that implements a multiplayer Pong game with advanced features including real-time gameplay, live chat, user management, and comprehensive security measures.
This repository focuses on the User Management and 2FA Authentication Module, which provides:
- Standard User Management: User registration, authentication, and profile management across tournaments
- Remote Authentication: Secure OAuth integration for third-party login providers
- Two-Factor Authentication (2FA): TOTP-based second layer of security using authenticator apps
- JWT Token Management: Stateless authentication with refresh token rotation
- Cybersecurity Best Practices: Implementation of WAF/ModSecurity and HashiCorp Vault for secrets management
- Backend Framework: NestJS (TypeScript)
- Frontend Framework: React/Next.js with TypeScript
- Database: PostgreSQL
- Containerization: Docker & Docker Compose
- Authentication: JWT + TOTP (Time-based One-Time Password)
- Security: ModSecurity WAF, HashiCorp Vault
- Yichun: User Management, 2FA/JWT Implementation, WAF/ModSecurity, HashiCorp Vault
- Arthur: Remote Authentication, Infrastructure & Log Management, DevOps
- Armel: Standard User Management & Tournament Integration
- Diego: Gameplay, Multiplayer, AI Opponent
- Jojo: Database, Live Chat, SSR Integration
- JWT.io - Official JWT Documentation
- OWASP Authentication Cheat Sheet
- NestJS Authentication Guide
- Passport.js Documentation
- RFC 6238 - TOTP: Time-Based One-Time Password Algorithm
- Google Authenticator Implementation
- Speakeasy - 2FA Library for Node.js
- QRCode.js - QR Code Generation
JWT is a compact, URL-safe token format used for securely transmitting information between parties. In this project, JWTs are used for stateless authentication, containing user identity and permissions.
Key Features:
- Stateless: No server-side session storage required
- Secure: Signed tokens prevent tampering
- Scalable: Easy to distribute across microservices
- Self-contained: Carries user information in the token payload
2FA adds an extra security layer beyond passwords by requiring a second verification method. This project implements TOTP (Time-based One-Time Password) using authenticator apps like Google Authenticator or Authy.
How TOTP Works:
- Server generates a secret key for the user
- Secret is shared with user via QR code
- User's authenticator app generates time-based 6-digit codes
- Server validates codes by computing expected value based on shared secret and current time
// Access Token: Short-lived (15min), contains user info
// Refresh Token: Long-lived (7d), used to generate new access tokens- Library:
speakeasyfor TOTP generation/verification - QR Code:
qrcodefor generating QR codes - Algorithm: SHA-1 based HMAC (RFC 6238 standard)
- Time Step: 30 seconds
- Code Length: 6 digits
- Secrets stored in HashiCorp Vault
- Rate limiting on authentication endpoints
- Encrypted storage of 2FA secrets
- Backup codes for account recovery
- IP-based suspicious activity detection
┌──────────────────────────────────────────────────────────────────────────┐
│ 🌍 CLIENT / USER │
│──────────────────────────────────────────────────────────────────────────│
│ Access via → https://localhost:3000 🔒 │
│ - Web Browser (React/Next.js Frontend) │
│ - Authenticator App (Google Authenticator, Authy, etc.) │
└──────────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ 🛡️ WAF / ModSecurity Layer │
│──────────────────────────────────────────────────────────────────────────│
│ • Request filtering & validation │
│ • OWASP Core Rule Set (CRS) │
│ • SQL Injection & XSS protection │
│ • Rate limiting & DDoS mitigation │
└──────────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ 🎮 NESTJS BACKEND APPLICATION │
│──────────────────────────────────────────────────────────────────────────│
│ 📦 Module Structure: │
│ ├─ 🔐 Auth Module (JWT + 2FA) │
│ │ ├─ Login/Logout endpoints │
│ │ ├─ JWT token generation/validation │
│ │ ├─ 2FA setup & verification │
│ │ └─ Refresh token rotation │
│ │ │
│ ├─ 👤 User Module │
│ │ ├─ User CRUD operations │
│ │ ├─ Profile management │
│ │ └─ Tournament participation tracking │
│ │ │
│ ├─ 🎯 Game Module │
│ │ ├─ Multiplayer game logic │
│ │ ├─ Real-time WebSocket connections │
│ │ └─ AI opponent integration │
│ │ │
│ ├─ 💬 Chat Module │
│ │ └─ Live chat functionality │
│ │ │
│ └─ 📊 Stats Module │
│ └─ User & game statistics dashboard │
│ │
│ 🔒 Security Layer: │
│ ├─ Guards: JWT, 2FA, Role-based │
│ ├─ Interceptors: Logging, transformation │
│ └─ Pipes: Validation, sanitization │
└──────────────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌────────────────────────────────┐ ┌────────────────────────────────┐
│ 🗄️ PostgreSQL Database │ │ 🔐 HashiCorp Vault │
│────────────────────────────────│ │────────────────────────────────│
│ • Users table │ │ • JWT secrets │
│ • 2FA secrets (encrypted) │ │ • Database credentials │
│ • Game records │ │ • API keys │
│ • Chat messages │ │ • Encryption keys │
│ • Tournament data │ │ • OAuth client secrets │
└────────────────────────────────┘ └────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────┐
│ 📊 Monitoring & Logging │
│──────────────────────────────────────────────────────────────────────────│
│ • ELK Stack (Elasticsearch, Logstash, Kibana) │
│ • Authentication attempts logging │
│ • Security event monitoring │
│ • Performance metrics │
└──────────────────────────────────────────────────────────────────────────┘
Data Flow:
- Client → User accesses application via browser
- WAF → Requests filtered through ModSecurity rules
- Backend → NestJS handles business logic & authentication
- Database → PostgreSQL stores user data & game state
- Vault → Secrets management for sensitive credentials
- Monitoring → Logs & metrics collected for analysis
┌──────────────────────────────────────────────────────────────────────────┐
│ 🔐 AUTHENTICATION FLOW │
└──────────────────────────────────────────────────────────────────────────┘
═══════════════════════════════════════════════════════════════════════════
📝 REGISTRATION PHASE
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ POST /auth/register │ │
│ {email, password} │ │
├──────────────────────>│ │
│ │ │
│ │ Hash password │
│ │ (bcrypt) │
│ │ │
│ │ CREATE user │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ User created │
│ │ │
│<──────────────────────┤ │
│ {success: true} │ │
│ │ │
═══════════════════════════════════════════════════════════════════════════
🔑 INITIAL LOGIN (Without 2FA)
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ POST /auth/login │ │
│ {email, password} │ │
├──────────────────────>│ │
│ │ │
│ │ Validate credentials │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ User found │
│ │ │
│ │ Check 2FA enabled? │
│ │ NO │
│ │ │
│ │ Generate JWT tokens: │
│ │ - Access Token (15m) │
│ │ - Refresh Token (7d) │
│ │ │
│<──────────────────────┤ │
│ {accessToken, │ │
│ refreshToken} │ │
│ │ │
═══════════════════════════════════════════════════════════════════════════
🔐 2FA SETUP PHASE
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │ │ Vault │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │ │
│ POST /2fa/setup │ │ │
│ {Authorization} │ │ │
├─────────────────>│ │ │
│ │ │ │
│ │ Validate JWT │ │
│ │ │ │
│ │ Generate secret │ │
│ │ (32-char base32) │ │
│ │ │ │
│ │ Store encrypted │ │
│ │ secret │ │
│ ├─────────────────>│ │
│ │ │ │
│ │ Get encryption │ │
│ │ key │ │
│ ├──────────────────┼─────────────────>│
│ │ │ │
│ │<─────────────────┼──────────────────┤
│ │ Encryption key │ │
│ │ │ │
│ │ Generate QR code │ │
│ │ (otpauth://...) │ │
│ │ │ │
│<─────────────────┤ │ │
│ {qrCode, │ │ │
│ secret, │ │ │
│ backupCodes} │ │ │
│ │ │ │
│ 📱 Scan QR with │ │ │
│ Authenticator App│ │ │
│ │ │ │
═══════════════════════════════════════════════════════════════════════════
✅ 2FA VERIFICATION & ACTIVATION
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ POST /2fa/verify │ │
│ {token: "123456"} │ │
├──────────────────────>│ │
│ │ │
│ │ Get user's secret │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ Encrypted secret │
│ │ │
│ │ Decrypt secret │
│ │ │
│ │ Verify TOTP: │
│ │ speakeasy.verify({ │
│ │ secret, │
│ │ encoding: 'base32', │
│ │ token: '123456', │
│ │ window: 1 │
│ │ }) │
│ │ │
│ │ Enable 2FA for user │
│ ├──────────────────────>│
│ │ │
│<──────────────────────┤ │
│ {success: true, │ │
│ twoFactorEnabled} │ │
│ │ │
═══════════════════════════════════════════════════════════════════════════
🔑 LOGIN WITH 2FA (Complete Flow)
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ [STEP 1] POST /login │ │
│ {email, password} │ │
├──────────────────────>│ │
│ │ │
│ │ Validate credentials │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ User found │
│ │ │
│ │ Check 2FA enabled? │
│ │ YES ✓ │
│ │ │
│ │ Generate temp token │
│ │ (5min expiry) │
│ │ │
│<──────────────────────┤ │
│ {requires2FA: true, │ │
│ tempToken} │ │
│ │ │
│ [STEP 2] Prompt user │ │
│ for 2FA code │ │
│ 📱 Get code from app │ │
│ (e.g., "654321") │ │
│ │ │
│ POST /2fa/authenticate│ │
│ {tempToken, code} │ │
├──────────────────────>│ │
│ │ │
│ │ Validate temp token │
│ │ │
│ │ Get user's 2FA secret │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ Encrypted secret │
│ │ │
│ │ Verify TOTP code │
│ │ ✓ Valid │
│ │ │
│ │ Generate final tokens:│
│ │ - Access Token (15m) │
│ │ - Refresh Token (7d) │
│ │ │
│ │ Store refresh token │
│ ├──────────────────────>│
│ │ │
│<──────────────────────┤ │
│ {accessToken, │ │
│ refreshToken, │ │
│ user} │ │
│ │ │
═══════════════════════════════════════════════════════════════════════════
🔄 TOKEN REFRESH FLOW
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ POST /auth/refresh │ │
│ {refreshToken} │ │
├──────────────────────>│ │
│ │ │
│ │ Verify refresh token │
│ │ signature │
│ │ │
│ │ Check token in DB │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ Token valid │
│ │ │
│ │ Generate new tokens: │
│ │ - New Access (15m) │
│ │ - New Refresh (7d) │
│ │ │
│ │ Revoke old refresh │
│ │ Store new refresh │
│ ├──────────────────────>│
│ │ │
│<──────────────────────┤ │
│ {accessToken, │ │
│ refreshToken} │ │
│ │ │
═══════════════════════════════════════════════════════════════════════════
🔓 LOGOUT FLOW
═══════════════════════════════════════════════════════════════════════════
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │ │ Backend │ │ Database │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ POST /auth/logout │ │
│ {refreshToken} │ │
├──────────────────────>│ │
│ │ │
│ │ Revoke refresh token │
│ ├──────────────────────>│
│ │ │
│ │<──────────────────────┤
│ │ Token revoked │
│ │ │
│<──────────────────────┤ │
│ {success: true} │ │
│ │ │
│ Clear local tokens │ │
│ │ │
Key Components:
-
JWT Token Structure
Access Token (15min): { "sub": "user-id", "email": "user@example.com", "roles": ["user"], "iat": 1234567890, "exp": 1234568790 } Refresh Token (7 days): { "sub": "user-id", "tokenId": "unique-token-id", "iat": 1234567890, "exp": 1235172690 } -
TOTP Algorithm
- Time Step: 30 seconds
- Code Length: 6 digits
- Algorithm: HMAC-SHA1
- Window: ±1 (accepts codes from previous/next time step)
-
Security Features
- Password hashing with bcrypt (salt rounds: 10)
- 2FA secrets encrypted at rest
- Refresh token rotation (each use generates new token)
- Token blacklisting on logout
- Rate limiting on auth endpoints (max 5 attempts/min)
# Clone the repository
git clone https://github.com/ychun816/Ft_transcendence.git
cd Ft_transcendence
# Install Dev Container extension in VS Code
# Press Ctrl+Shift+P → "Dev Containers: Reopen in Container"
# Inside the container, start the development server
npm run dev
# Server will run on https://localhost:3000curl -X POST https://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "testuser@example.com",
"password": "SecurePass123!",
"username": "testuser"
}'curl -X POST https://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "testuser@example.com",
"password": "SecurePass123!"
}'# Replace {ACCESS_TOKEN} with the token from login response
curl -X POST https://localhost:3000/api/2fa/setup \
-H "Authorization: Bearer {ACCESS_TOKEN}"
# Response includes:
# - qrCode: base64 image to scan with authenticator app
# - secret: manual entry key (if QR scan fails)
# - backupCodes: emergency recovery codesOr use the temporary endpoint:
# Setup TOTP for a specific user (development only)
https://localhost:3000/api/2fa/setup-totp-temp/testuser# Get 6-digit code from Google Authenticator app
curl -X POST https://localhost:3000/api/2fa/verify \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"token": "123456"
}'Or use the temporary endpoint:
# Verify TOTP for a specific user (development only)
https://localhost:3000/api/2fa/verify-totp-temp/testuser/123456Step 1: Initial Login
curl -X POST https://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "testuser@example.com",
"password": "SecurePass123!"
}'
# Response:
# {
# "requires2FA": true,
# "tempToken": "temporary-5min-token"
# }Step 2: Complete with 2FA
# Get current 6-digit code from authenticator app
curl -X POST https://localhost:3000/api/2fa/authenticate \
-H "Content-Type: application/json" \
-d '{
"tempToken": "temporary-5min-token",
"code": "654321"
}'
# Response:
# {
# "accessToken": "jwt-access-token",
# "refreshToken": "jwt-refresh-token",
# "user": { ... }
# }curl -X POST https://localhost:3000/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "{REFRESH_TOKEN}"
}'curl -X GET https://localhost:3000/api/users/profile \
-H "Authorization: Bearer {ACCESS_TOKEN}"curl -X POST https://localhost:3000/api/2fa/disable \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"password": "SecurePass123!"
}'curl -X POST https://localhost:3000/api/auth/logout \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "{REFRESH_TOKEN}"
}'To run the docker:
- Download "Dev Container" from Microsoft on Vs Code
- Make sure your port 3000 is free
- Inside VsCode, ctrl shift P to open menu & type Dev Container, (rebuild) reopen in container.
- Now you inside the container, BE CAREFUL WITH THIS, every you will do inside your container is also done in your repo on your computer, its a bind mount so make sure what you do.
- For exemple load 2 VsCode, connect one with the container & open another one in VsCode via your folder, everything you type in VsCode will appear in the other one.
- To run server:
npm run dev - Run the script if you want to reset docker images & containers, be aware, this script will remove all the Docker environment.
https://localhost:3000/api/2fa/setup-totp-temp/user
http://localhost:3000/api/2fa/verify-totp-temp/userr/2fanumber
# Remove all Docker images and containers (USE WITH CAUTION)
./reset_docker.sh
# View logs
docker-