Executive Summary
This document is a companion technical documentation for the Live Reference Application described in Section 10: Added Value of the Proposal for Consultancy Services — Senior Web Frontend Developer Consultant (TCIS). It details the end-to-end security architecture implemented for the AfDB enterprise portal: MFA-protected authentication flows, SSO-IDP federation with Google Workspace and Azure AD, OWASP Top 10 hardened frontend middleware, and a fully documented API layer — demonstrating the secure, production-ready web applications that the consultancy engagement will deliver.
The AfDB Reference Application is a modern, security-first enterprise web system designed to manage project data, reporting, and operational workflows for the African Development Bank. This live reference application demonstrates in practice the capabilities described in the consultancy proposal — a working, production-deployed system that evaluators can inspect, interact with, and verify.
MFA-Protected Access
Multi-factor authentication with TOTP authenticator apps and backup recovery codes
Implemented & VerifiedSSO-IDP Federation
Single Sign-On via OAuth2/OIDC with Google Workspace and Microsoft Azure AD
Implemented & VerifiedOWASP Top 10 Compliant
Industry-standard security hardening against the most critical web application threats
Implemented & VerifiedThe system is built as a microservices architecture with a dedicated Authentication Gateway (Beta Backend) that handles all security concerns, and a Data Service (Core Backend) that serves business logic. Both frontends authenticate exclusively through the hardened gateway.
- Zero-trust authentication model with layered security
- Protection against all OWASP Top 10 vulnerability categories
- Enterprise SSO federation with Google and Microsoft/Azure AD
- Account lockout protection against brute-force attacks
- Input sanitization blocking NoSQL injection and XSS attacks
- Comprehensive audit logging for all security events
Login Credentials & URLs
Use these credentials to access the live demo portals. Both portals share the same authentication backend (Beta). Login requires email OTP verification — after entering credentials, check the user's Yopmail inbox for the 6-digit code.
Portal URLs
| Portal | URL | Purpose |
|---|---|---|
| Auth Portal | http://localhost:3000/login | Authentication gateway — login, MFA, SSO, password reset |
| Enterprise Dashboard | http://localhost:3001/login | Business application — dashboard, projects, monitoring |
| API Documentation | http://localhost:4000/api-docs | Scalar API reference — explore all backend endpoints |
Demo Accounts
| Role | Password | Portal | Permissions | |
|---|---|---|---|---|
| Admin | afdbadmin@yopmail.com |
Admin@123 |
:3000 · :3001 | Full access — all features, user management, monitoring |
| Viewer | afdbaviewer@yopmail.com |
Viewer@123 |
:3000 · :3001 | Read-only access — view dashboards, projects, reports |
| Manager | afdbmanager@yopmail.com |
Manager@123 |
:3000 · :3001 | Project management — create, edit, approve projects (role: staff) |
System Architecture
2.1 High-Level Architecture
2.2 Authentication Flow
2.3 Microservices Design — Beta & Core
The platform is built as two separate microservices that work together. AfDB Beta handles identity (who you are), and AfDB Core handles business operations (what you do). This separation of concerns ensures that authentication logic is isolated, independently scalable, and reusable across future services.
Service Comparison
| Concern | Beta (port 4000) | Core (port 4001) |
|---|---|---|
| Database | afdb_beta — users, tokens, sessions | afdb_core — projects, activities, reports |
| API Endpoints | /auth/login, /auth/signup, /auth/verify-mfa, /auth/refresh, /auth/logout, /sso/* | /projects/*, /dashboard/* |
| Security | Helmet, rate limiting, input sanitization, security headers, OWASP compliance | Basic Helmet + CORS; trusts Beta's JWT |
| SSO Providers | Google OAuth2, Microsoft / Azure AD | None — validates tokens issued by Beta |
| Frontend Pages | Login, Signup, MFA verification, Password reset, SSO callback | Dashboard, Projects, Reports |
| Role | Auth Gateway — the gatekeeper | Business Engine — the application |
Concrete Examples
localhost:3000/loginPOST localhost:4000/api/v1/auth/login{ "mfaRequired": true, "userId": "abc123" }POST /api/v1/auth/verify-mfa with TOTP codeaccessToken + refreshToken/dashboardlocalhost:3001/projectsGET localhost:4001/api/v1/projects with Authorization: Bearer eyJ...afdb_core databaseIf the JWT is missing or invalid, Core returns 401 Unauthorized — the user must re-authenticate through Beta.
GET /api/v1/sso/callback/google?code=...JWT_ACCESS_EXPIRY)POST /api/v1/auth/refresh with refreshTokenaccessToken — Core continues working seamlesslyBeta is the gatekeeper — it issues the JWT that Core trusts. Core never handles passwords or MFA; it just validates the token Beta signed. This means authentication logic can be updated, scaled, or replaced independently without touching business logic.
2.4 Cross-Service Activity Monitoring (Diagnostic Tool)
Building on the microservices design, the platform includes a real-time activity monitoring system that turns Core into a diagnostic tool for tracking every user action performed through the Beta auth portal. Beta emits structured activity events to Core via an internal API, and Core provides a monitoring dashboard for security analysis and operational awareness.
Tracked Auth Events
| Event | Action Key | Severity | Status | Source Controller |
|---|---|---|---|---|
| Successful login | auth.login | info | success | auth.controller |
| Failed login | auth.login_failed | warning | failure | auth.controller |
| Account locked | auth.account_locked | critical | failure | auth.controller |
| MFA verified | auth.mfa_verified | info | success | auth.controller |
| MFA failed | auth.mfa_failed | warning | failure | auth.controller |
| Account signup | auth.signup | info | success | auth.controller |
| Password changed | auth.password_changed | info | success | auth.controller |
| Token refresh | auth.token_refresh | info | success | auth.controller |
| Logout | auth.logout | info | success | auth.controller |
| SSO login | auth.sso_login | info | success | sso.controller |
| SSO callback failed | auth.sso_failed | warning | failure | sso.controller |
| MFA enabled | auth.mfa_enabled | info | success | mfa.controller |
| MFA disabled | auth.mfa_disabled | warning | success | mfa.controller |
| Backup codes regenerated | auth.backup_codes_regenerated | warning | success | mfa.controller |
Activity Event Schema
Each event emitted by Beta and stored in Core includes the following diagnostic fields:
{
"action": "auth.login", // Event type identifier
"userId": "66a1b2c3d4e5f6...", // User who performed the action
"userName": "John Doe", // Display name
"userEmail": "john@afdb.org", // User email address
"severity": "info", // info | warning | critical
"status": "success", // success | failure
"ipAddress": "192.168.1.42", // Client IP (from x-forwarded-for)
"userAgent": "Mozilla/5.0...", // Browser/device string
"source": "beta", // Originating service
"details": { "role": "admin" }, // Arbitrary extra context
"createdAt": "2026-08-29T10:30:00Z" // Timestamp (auto)
}
Monitoring Dashboard Features
The Core frontend at localhost:3001/monitoring provides a full diagnostic interface:
Total events (24h), active users, failed attempts, and critical alerts — at a glance.
Clickable chips showing event distribution — click any action type to filter the feed.
Paginated list with severity badges, user info, IP addresses, timestamps, and event details.
Filter by action type, severity, status. Click any user to see their full activity timeline.
Activity API Endpoints
| Method | Endpoint | Auth | Purpose |
|---|---|---|---|
POST | /api/v1/activities | x-api-key (internal) | Beta emits events to Core |
GET | /api/v1/activities | JWT (frontend) | Paginated activity feed with filters |
GET | /api/v1/activities/stats | JWT (frontend) | Aggregated stats (24h/7d breakdowns) |
GET | /api/v1/activities/users/:id | JWT (frontend) | Per-user activity timeline |
The activity emitter uses a fire-and-forget pattern — Beta sends events to Core via HTTP POST and never blocks on failures. If Core is temporarily unavailable, auth operations continue normally. Events are logged as warnings but never interrupt the user experience. This ensures the monitoring layer adds zero risk to the authentication flow.
Technology Stack
3.1 Frontend
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 15.x | React framework with SSR/SSG |
| React | 19.x | UI component library |
| TypeScript | 5.5.x | Type-safe development |
| Tailwind CSS | 3.4.x | Utility-first styling |
| Ant Design | 5.20.x | Enterprise UI components |
| TanStack React Query | 5.51.x | Server state management |
| Axios | 1.7.x | HTTP client with interceptors |
| Lucide React | 1.34.x | Icon library |
| next-themes | 0.4.x | Dark/light mode support |
3.2 Backend
| Technology | Version | Purpose |
|---|---|---|
| Node.js + Express | 4.21.x | API server framework |
| TypeScript | 5.5.x | Type-safe development |
| MongoDB + Mongoose | 8.6.x | Primary data store (NoSQL) |
| Redis + ioredis | 5.4.x | Caching & session store |
| JSON Web Token | 9.0.x | Token-based authentication |
| bcryptjs | 2.4.x | Password hashing (12 rounds) |
| otplib | 13.5.x | TOTP multi-factor authentication |
| Helmet | 7.1.x | HTTP security headers |
| express-rate-limit | 7.4.x | Brute-force protection |
| QRCode | 1.5.x | MFA setup QR generation |
| Winston | 3.14.x | Structured logging |
| Scalar | latest | API documentation |
3.3 Infrastructure
| Component | Technology | Port |
|---|---|---|
| Beta Frontend | Next.js | 3000 |
| Core Frontend | Next.js | 3001 |
| Beta Backend (Auth Gateway) | Express.js | 4000 |
| Core Backend (Data Service) | Express.js | 4001 |
| Database | MongoDB | 27017 |
| Cache | Redis | 6379 |
| API Documentation | Scalar | 4000/api-docs |
Security Implementation: MFA-Protected Access
4.1 Overview
Multi-Factor Authentication (MFA) adds a critical second layer of verification beyond passwords. Users must provide both something they know (password) and something they have (authenticator app or backup code).
4.2 TOTP Implementation
| Property | Detail |
|---|---|
| Algorithm | TOTP per RFC 6238 via otplib v13 |
| Secret Generation | Cryptographically random 32-character base32 secret |
| QR Code | Generated as data URL for authenticator app scanning |
| Verification | Time-windowed token validation with drift tolerance |
| Issuer Label | "AfDB Secure Portal" |
4.3 Backup Codes
| Property | Detail |
|---|---|
| Quantity | 10 unique codes per user |
| Format | 8-character uppercase hexadecimal (e.g., A3F7B2C1) |
| Storage | bcrypt-hashed (10 rounds) — plaintext never stored |
| Usage | One-time use; marked used: true after verification |
| Regeneration | Users can generate a fresh set of 10 codes anytime |
| Warning | System alerts when 3 or fewer codes remain |
4.4 MFA API Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/mfa/setup | Yes | Generate MFA secret & QR code |
| POST | /api/v1/mfa/verify | Yes | Verify TOTP token and enable MFA |
| POST | /api/v1/mfa/verify-backup | Yes | Verify a backup code |
| POST | /api/v1/mfa/regenerate-backup-codes | Yes | Generate new backup code set |
| GET | /api/v1/mfa/status | Yes | Check MFA status & remaining codes |
| POST | /api/v1/mfa/disable | Yes | Disable MFA and clear secrets |
4.5 MFA User Flow
Email OTP Verification
5.1 Overview
The platform implements email-based One-Time Password (OTP) verification across all authentication flows — login, registration, and password reset. Every user who logs in must verify their identity via a 6-digit code sent to their email address, providing a robust second factor that doesn't require a separate authenticator app.
Login Verification
6-digit code sent after credentials verified — required for every login attempt
Registration Verification
Email ownership confirmed before account creation — prevents fake registrations
Password Reset
Secure code required before password change — protects account recovery flow
5.2 OTP Architecture
| Property | Detail |
|---|---|
| Code Format | 6-digit numeric code (100000–999999) |
| Storage | Redis with TTL-based auto-expiry |
| Expiry | 600 seconds (10 minutes) — matches countdown timer in UI |
| Key Pattern | {purpose}_otp:{identifier} — e.g., login_otp:userId, register_otp:email, reset_otp:email |
| Delivery | SMTP via Nodemailer with embedded logo (CID attachment) |
| Security | Single-use (deleted from Redis after verification), rate-limited endpoints |
| Enumeration Prevention | Password reset returns success even for unregistered emails |
5.3 Authentication Flows with OTP
Login Flow (Email OTP as 2FA)
Registration Flow (Email Verification)
Password Reset Flow
5.4 Professional Email Templates
OTP emails use professional, branded HTML templates with the AfDB logo embedded via CID (Content-ID) attachment. Each purpose has a distinct accent color and messaging:
| Purpose | Accent Color | Subject Line Format | Icon |
|---|---|---|---|
| 2FA Setup | ■ Green (#009A44) | {OTP} is your AfDB 2FA Verification Code | |
| Login | ■ Blue (#1565C0) | {OTP} is your AfDB Login Verification Code | |
| Registration | ■ Green (#009A44) | {OTP} is your AfDB Registration Verification Code | |
| Password Reset | ■ Orange (#E65100) | {OTP} is your AfDB Password Reset Code |
- Embedded Logo — AfDB logo rendered inline via CID attachment (works in all email clients)
- Table-based HTML — Maximum compatibility across Outlook, Gmail, Apple Mail, and mobile clients
- MSO Conditionals — Special handling for Microsoft Outlook rendering
- Responsive Design — Media queries for mobile devices (max-width: 600px)
- Security Reminder — Warning to never share the verification code
- Branded Footer — AfDB address (Abidjan, Côte d'Ivoire), copyright notice
- Purpose-Specific Styling — Each email type has distinct color, icon, and messaging
5.5 Frontend OTP UX
The OTP verification component provides a polished user experience:
- 6 individual input fields — One per digit, auto-focus advancement
- Paste support — Users can paste a full 6-digit code (e.g., from email); digits are distributed across fields automatically
- Countdown timer — 10:00 minute countdown matching the Redis TTL, displayed below the OTP fields
- Color-coded expiry — Gray (normal) → Orange (≤2 min remaining) → Red (expired)
- Auto-disable on expiry — Verify button disabled when code expires; message prompts to resend
- Resend functionality — New code sent, timer resets to 10:00
- Auto-verify — When all 6 digits are entered, verification is submitted automatically
5.6 Retrieving OTP During Testing (Yopmail)
The demo environment uses Yopmail as the email provider for testing. Yopmail is a disposable email service that allows anyone to view the inbox of any @yopmail.com address without a password.
- Attempt login at http://localhost:3000/login with credentials (e.g.,
afdbadmin@yopmail.com) - After credentials are accepted, the UI will show the OTP verification screen
- Open a new browser tab and go to https://yopmail.com
- Type the email username in the inbox field (e.g.,
afdbadmin) — no need to type@yopmail.com - Click "Check Inbox" (or the arrow button)
- Find the email with subject like
"123456 is your AfDB Login Verification Code" - The 6-digit OTP is displayed prominently in the email body — copy or note it
- Enter the code in the OTP fields on the login page (or paste all 6 digits at once)
- OTP expires in 10 minutes — if the timer reaches zero, click "Resend Code" to get a new one
- Yopmail inboxes are public — anyone can read emails sent to
@yopmail.comaddresses. Never use for production! - Direct inbox link — You can also go directly to
https://yopmail.com/en/?afdbadmin(replaceafdbadminwith the username) - Email may take 10–30 seconds — SMTP delivery is not instant; refresh the Yopmail inbox if the email doesn't appear immediately
5.7 OTP API Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/auth/send-login-otp | No | Send login OTP (requires userId from login response) |
| POST | /api/v1/auth/verify-login-otp | No | Verify login OTP and issue JWT tokens |
| POST | /api/v1/auth/send-register-otp | No | Send registration OTP (requires email) |
| POST | /api/v1/auth/verify-register-otp | No | Verify registration OTP and create account |
| POST | /api/v1/auth/send-reset-otp | No | Send password reset OTP (requires email) |
| POST | /api/v1/auth/verify-reset-otp | No | Verify reset OTP and update password |
| POST | /api/v1/auth/send-otp | Yes | Send OTP for 2FA setup (authenticated user) |
| POST | /api/v1/auth/verify-otp | Yes | Verify 2FA setup OTP |
5.8 SMTP Configuration
Email delivery is configured via environment variables in the Beta Backend:
SMTP_HOST=smtp.hostinger.com SMTP_PORT=465 SMTP_USER=no-reply@atradezone.ca SMTP_PASSWORD=<smtp-password> SMTP_FROM=no-reply@atradezone.ca
| Variable | Description | Default |
|---|---|---|
SMTP_HOST | SMTP server hostname | smtp.hostinger.com |
SMTP_PORT | SMTP port (465 for SSL, 587 for TLS) | 465 |
SMTP_USER | SMTP authentication username | — |
SMTP_PASSWORD | SMTP authentication password | — |
SMTP_FROM | Sender email address (From header) | no-reply@atradezone.ca |
Security Implementation: SSO-IDP Federation
6.1 Overview
Single Sign-On (SSO) federation allows users to authenticate through their organization's existing identity provider without managing separate credentials. This implementation follows the OAuth 2.0 Authorization Code Flow.
6.2 Supported Identity Providers
| Provider | Protocol | Authorization Endpoint | User Info Endpoint |
|---|---|---|---|
| OAuth 2.0 / OIDC | accounts.google.com/o/oauth2/v2/auth | googleapis.com/oauth2/v2/userinfo | |
| Microsoft / Azure AD | OAuth 2.0 / OIDC | login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize | graph.microsoft.com/v1.0/me |
6.3 Security Measures
| Measure | Implementation |
|---|---|
| CSRF Protection | Cryptographic state parameter (crypto.randomBytes(32)) validated with timing-safe comparison |
| Token Exchange | Server-side code exchange (never exposed to client) |
| State Expiry | States expire after 10 minutes to prevent replay attacks |
| Auto-Provisioning | New SSO users automatically created with viewer role |
| Account Linking | Existing accounts linked to SSO provider on first login |
| Provider Discovery | Only configured providers appear (no information leakage) |
6.4 SSO API Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/sso/providers | No | List available SSO providers |
| GET | /api/v1/sso/initiate/:providerId | No | Start OAuth flow, returns authorization URL |
| GET | /api/v1/sso/callback/:providerId | No | Handle OAuth callback with authorization code |
6.5 SSO Authentication Sequence
Security Implementation: OWASP Top 10 Compliance
7.1 Compliance by Category
A01: Broken Access Control
| Control | Implementation | Status |
|---|---|---|
| Security Headers | Helmet.js with strict Content Security Policy | Verified |
| CORS | Restricted to approved origins only | Verified |
| X-Frame-Options | DENY — prevents clickjacking | Verified |
| Auth Middleware | All protected routes require valid JWT | Verified |
| Role-Based Access | admin, staff, viewer roles enforced | Verified |
A02: Cryptographic Failures
| Control | Implementation | Status |
|---|---|---|
| Password Hashing | bcrypt with 12 salt rounds | Verified |
| Transport Security | HSTS with 1-year max-age | Verified |
| Token Security | JWT with short expiry (30 minutes) | Verified |
| Refresh Tokens | UUID v4, stored server-side, revocable | Verified |
| Body Size Limit | 10KB maximum request body | Verified |
| Cache Prevention | Cache-Control: no-store on all responses | Verified |
A03: Injection
| Control | Implementation | Status |
|---|---|---|
| NoSQL Injection | Blocks MongoDB operators ($gt, $regex, $where, etc.) as both values AND keys | Verified |
| XSS Injection | Blocks <script>, javascript:, on\w+=, <iframe>, <object> | Verified |
| Key Sanitization | Replaces $ and . in object keys with _ | Verified |
| String Length | 10,000 character maximum per value | Verified |
| Parameterized Queries | Mongoose ODM prevents direct query injection | Verified |
{"email": {"$gt": ""}} → 400 "Invalid input detected"XSS Injection:
{"firstName": "<script>alert(1)</script>"} → 400 "Invalid input detected"
A04: Insecure Design
| Control | Implementation | Status |
|---|---|---|
| API Rate Limiting | 100 requests/minute (general API) | Verified |
| Login Rate Limiting | 5 attempts per 15 minutes per IP | Verified |
| Account Lockout | 5 failed logins → 15-minute lockout | Verified |
| Password Policy | OWASP-compliant strength requirements | Verified |
A05: Security Misconfiguration
| Control | Implementation | Status |
|---|---|---|
| Helmet | Comprehensive HTTP header hardening | Verified |
| X-Powered-By | Removed from responses | Verified |
| Permissions-Policy | Camera, microphone, geolocation disabled | Verified |
| Cross-Origin Policies | COEP, COOP, CORP all enforced | Verified |
| Error Handling | Centralized handler prevents stack trace leakage | Verified |
A07: Identification & Authentication
| Control | Implementation | Status |
|---|---|---|
| Account Lockout | 5 attempts → 15 min lock, with user feedback | Verified |
| Password Strength | Min 8 chars, uppercase, lowercase, digit, special char | Verified |
| MFA | TOTP + backup codes | Verified |
| Session Management | JWT access (30min) + refresh (30 days) tokens | Verified |
| Token Revocation | All tokens revoked on password change or logout | Verified |
A09: Logging & Monitoring
| Control | Implementation | Status |
|---|---|---|
| HTTP Logging | Morgan combined format → Winston structured logs | Verified |
| Security Events | MFA enable/disable, backup code usage, account lockout | Verified |
| Auth Events | Login success/failure, token refresh, logout | Verified |
| Health Check | /health endpoint for monitoring | Verified |
7.2 Security Middleware Stack
The middleware stack is ordered for defense-in-depth. Each layer processes the request before it reaches the route handler:
Verified HTTP Response Headers
X-Frame-Options: DENY X-Content-Type-Options: nosniff Strict-Transport-Security: max-age=31536000; includeSubDomains Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'... Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() Cache-Control: no-store X-XSS-Protection: 1; mode=block
API Reference
8.1 Interactive API Documentation (Scalar)
The Beta Backend provides a modern, interactive API documentation powered by Scalar. This allows you to explore, test, and understand all available endpoints directly from your browser.
Interactive documentation with "Try it" functionality
http://localhost:4000/api-docs
Raw OpenAPI 3.0 specification for import into tools
http://localhost:4000/api-docs.json
- Try it — Execute API requests directly from the documentation
- Code snippets — Auto-generated examples in curl, JavaScript, Python, and more
- Search — Quickly find endpoints across Auth, MFA, and SSO
- Dark mode — Toggle between light and dark themes
- Import to Postman — Download the JSON spec and import into Postman for advanced testing
8.2 System Services & Ports
The AfDB platform consists of four services that work together in a microservices architecture:
| Service | Port | URL | Responsibility |
|---|---|---|---|
| Beta Frontend | 3000 | http://localhost:3000 |
Authentication UI — Login, Signup, MFA verification |
| Beta Backend | 4000 | http://localhost:4000 |
Authentication Gateway — MFA, JWT, SSO-IDP, OWASP security |
| Core Frontend | 3001 | http://localhost:3001 |
Application UI — Dashboard, Projects, Reports |
| Core Backend | 4001 | http://localhost:4001 |
Data Service — Business logic, project management |
8.3 Service Communication Flow
The diagram below illustrates how the frontends and backends communicate:
http://localhost:3000 (Beta Frontend) or http://localhost:3001 (Core Frontend)
http://localhost:4000/api/v1/* for authentication (login, MFA, SSO)
Authorization: Bearer <token> header
- Frontend API calls: Use
NEXT_PUBLIC_API_URL=http://localhost:4000/api/v1 - API Documentation: Available at
http://localhost:4000/api-docs - OpenAPI Spec: Available at
http://localhost:4000/api-docs.json
8.4 Authentication Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/auth/login | No | Authenticate with email/password (returns mfaRequired: true) |
| POST | /api/v1/auth/send-login-otp | No | Send login OTP to user's email |
| POST | /api/v1/auth/verify-login-otp | No | Verify login OTP and receive JWT tokens |
| POST | /api/v1/auth/signup | No | Register new account |
| POST | /api/v1/auth/send-register-otp | No | Send registration verification OTP |
| POST | /api/v1/auth/verify-register-otp | No | Verify registration OTP and create account |
| POST | /api/v1/auth/send-reset-otp | No | Send password reset OTP |
| POST | /api/v1/auth/verify-reset-otp | No | Verify reset OTP and update password |
| POST | /api/v1/auth/send-otp | Yes | Send OTP for 2FA setup |
| POST | /api/v1/auth/verify-otp | Yes | Verify 2FA setup OTP |
| POST | /api/v1/auth/verify-mfa | No | Verify MFA token (TOTP or backup code) |
| POST | /api/v1/auth/change-password | Yes | Change password (revokes all tokens) |
| POST | /api/v1/auth/refresh | No | Refresh access token |
| POST | /api/v1/auth/logout | Yes | Revoke all tokens |
| GET | /api/v1/auth/me | Yes | Get current user profile |
8.5 MFA Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/mfa/setup | Yes | Generate MFA secret & QR code |
| POST | /api/v1/mfa/verify | Yes | Verify TOTP and enable MFA |
| POST | /api/v1/mfa/verify-backup | Yes | Verify backup code |
| POST | /api/v1/mfa/regenerate-backup-codes | Yes | Regenerate backup codes |
| GET | /api/v1/mfa/status | Yes | Get MFA status |
| POST | /api/v1/mfa/disable | Yes | Disable MFA |
8.6 SSO Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/sso/handoff | No | SSO handoff from external IDP |
| POST | /api/v1/sso/generate | No | Generate SSO handoff token |
| GET | /api/v1/sso/providers | No | List configured SSO providers |
| GET | /api/v1/sso/initiate/:providerId | No | Start OAuth2 flow |
| GET | /api/v1/sso/callback/:providerId | No | OAuth2 callback handler |
Testing Scenarios & Results
9.1 Authentication Tests
| # | Scenario | Input | Expected Result | Actual Result | Status |
|---|---|---|---|---|---|
| 1 | Valid login | afdbadmin@yopmail.com / Admin@123 | 200 OK, mfaRequired: true | 200 OK, OTP sent | PASS |
| 2 | Invalid password | afdbadmin@yopmail.com / wrongpass | 401 Invalid credentials | 401 Invalid credentials | PASS |
| 3 | Missing fields | {} | 400 Required fields | 400 Email and password required | PASS |
| 4 | Account lockout | 5 consecutive wrong passwords | 423 Account locked | 423 Locked, 15min cooldown | PASS |
| 5 | Lockout warning | 3rd failed attempt | Warning shown | Orange alert, remaining count | PASS |
| 6 | New user signup | Valid registration data | 201 Created, JWT | 201 Created, auto-login | PASS |
| 7 | Weak password | password | 400 Too weak | 400 with requirements | PASS |
| 8 | Duplicate email | Existing email | 409 Already registered | 409 Already registered | PASS |
| 9 | Password change | Valid current + new | 200, tokens revoked | 200 Password changed | PASS |
9.2 MFA Tests
| # | Scenario | Input | Expected Result | Actual Result | Status |
|---|---|---|---|---|---|
| 1 | MFA setup | Authenticated user | Secret + QR returned | QR data URL generated | PASS |
| 2 | TOTP verify | Valid 6-digit code | 200, JWT issued | Tokens returned | PASS |
| 3 | TOTP invalid | Wrong code | 401 Invalid | 401 Invalid MFA token | PASS |
| 4 | Backup code | Valid backup code | 200, code consumed | Tokens, code marked used | PASS |
| 5 | Backup reuse | Same backup code | 401 Already used | 401 Invalid | PASS |
| 6 | Regenerate | Authenticated user | 10 new codes | New set generated | PASS |
| 7 | Remaining count | After using 3 codes | 7 remaining | Accurate count returned | PASS |
| 8 | MFA login flow | MFA-enabled user | Redirect to MFA | mfaRequired: true | PASS |
9.3 SSO Tests
| # | Scenario | Input | Expected Result | Actual Result | Status |
|---|---|---|---|---|---|
| 1 | Provider discovery | GET /sso/providers | List of providers | Empty (no env vars) | PASS |
| 2 | Provider configured | Google client ID set | Google in list | Provider with auth URL | PASS |
| 3 | OAuth initiate | GET /sso/initiate/google | Auth URL + state | URL generated, state stored | PASS |
| 4 | State validation | Valid state | State accepted | Timing-safe comparison | PASS |
| 5 | Invalid state | Wrong/expired state | 403 Invalid | 403 Forbidden | PASS |
| 6 | Auto-provision | New SSO email | User created | Created with viewer role | PASS |
| 7 | Account linking | Existing email + SSO | Provider linked | Provider linked | PASS |
9.4 Security Tests
| # | Scenario | Input | Expected | Actual | Status |
|---|---|---|---|---|---|
| 1 | NoSQL injection (value) | {"email": "$gt:''"} | 400 Blocked | 400 "Invalid input detected" | PASS |
| 2 | NoSQL injection (key) | {"email": {"$gt":""}} | 400 Blocked | 400 "Invalid input detected" | PASS |
| 3 | XSS injection | {"name": "<script>..."} | 400 Blocked | 400 "Invalid input detected" | PASS |
| 4 | iframe injection | {"bio": "<iframe>..."} | 400 Blocked | 400 "Invalid input detected" | PASS |
| 5 | Security headers | Any request | All headers present | HSTS, X-Frame, CSP, etc. | PASS |
| 6 | Rate limiting | 100+ req/min | 429 Throttled | 429 returned | PASS |
| 7 | Login rate limit | 5+ logins/15min | 429 Throttled | 429 returned | PASS |
| 8 | Body size limit | Request > 10KB | 413 Rejected | Request rejected | PASS |
| 9 | Cache prevention | Any API response | no-store header | Header present | PASS |
| 10 | Clickjacking | Embed in iframe | X-Frame: DENY | Header present | PASS |
9.5 Frontend UX Tests
| # | Scenario | Expected Result | Status |
|---|---|---|---|
| 1 | Login page renders | Email/password form, SSO buttons if configured | PASS |
| 2 | SSO buttons appear | Only when providers are configured | PASS |
| 3 | MFA page | TOTP input + backup code toggle | PASS |
| 4 | Signup password strength | Real-time strength bar with 5 rules | PASS |
| 5 | Account lockout warning | Orange alert with remaining attempts | PASS |
| 6 | SSO callback processing | Loading spinner → success/error state | PASS |
| 7 | Dark mode | Full dark/light theme support | PASS |
| 8 | Responsive design | Mobile, tablet, desktop layouts | PASS |
| 9 | OTP verification screen | 6-digit input with paste support, countdown timer | PASS |
| 10 | OTP paste | Paste 6-digit code fills all fields automatically | PASS |
| 11 | OTP expiry timer | 10:00 countdown, color changes at 2min and expired | PASS |
| 12 | OTP resend | New code sent, timer resets to 10:00 | PASS |
| 13 | Forgot password flow | Email → OTP → new password → success | PASS |
| 14 | Registration OTP flow | Form → OTP → verify → account created | PASS |
48 test cases executed across 5 categories — Authentication (9), MFA (8), SSO (7), Security (10), Frontend UX (14). All tests passed.
Deployment Architecture
10.1 Required Environment Variables
# Server PORT=4000 NODE_ENV=production MONGODB_URI=mongodb://host:27018/afdb_beta REDIS_HOST=localhost REDIS_PORT=6379 # JWT Secrets (use strong 256-bit random values) JWT_ACCESS_SECRET=<256-bit-random-secret> JWT_REFRESH_SECRET=<256-bit-random-secret> JWT_ACCESS_EXPIRY=30m JWT_REFRESH_EXPIRY=30d # CORS CORS_ORIGINS=https://portal.afdb.org,https://core.afdb.org # SSO — Google OAuth2 GOOGLE_CLIENT_ID=<google-oauth-client-id> GOOGLE_CLIENT_SECRET=<google-oauth-client-secret> GOOGLE_REDIRECT_URI=https://api.afdb.org/api/v1/sso/callback/google # SSO — Microsoft / Azure AD MICROSOFT_CLIENT_ID=<azure-ad-client-id> MICROSOFT_CLIENT_SECRET=<azure-ad-client-secret> MICROSOFT_TENANT_ID=<azure-tenant-id> MICROSOFT_REDIRECT_URI=https://api.afdb.org/api/v1/sso/callback/microsoft # Frontend FRONTEND_URL=https://portal.afdb.org # SMTP (Email OTP Delivery) SMTP_HOST=smtp.afdb.org SMTP_PORT=465 SMTP_USER=noreply@afdb.org SMTP_PASSWORD=<smtp-password> SMTP_FROM=noreply@afdb.org
10.2 Production Readiness Checklist
- Set strong
JWT_ACCESS_SECRETandJWT_REFRESH_SECRET(min 256-bit) - Configure MongoDB with authentication and TLS/SSL
- Enable Redis persistence and authentication
- Set
NODE_ENV=production - Configure TLS/SSL certificates for all endpoints
- Set up Google and/or Microsoft OAuth2 credentials
- Configure
CORS_ORIGINSwith production domains - Enable MongoDB audit logging
- Set up log aggregation (Winston → centralized logging platform)
- Configure health check monitoring on
/health - Configure SMTP credentials for email OTP delivery
- Set up alerting for account lockout events
- Run security penetration testing before go-live
Compliance Matrix
11.1 OWASP Top 10 (2021) — Full Coverage
| Category | Risk | Controls Implemented | Tests |
|---|---|---|---|
| A01: Broken Access Control | High | Helmet, CORS, X-Frame-Options, Auth Middleware, RBAC | 5 |
| A02: Cryptographic Failures | High | bcrypt, HSTS, JWT, body limits, cache prevention | 7 |
| A03: Injection | High | Input sanitizer (NoSQL + XSS), key sanitization, string limits | 4 |
| A04: Insecure Design | High | Rate limiting, account lockout, password policy | 3 |
| A05: Security Misconfiguration | Medium | Helmet, Permissions-Policy, header hardening | 6 |
| A06: Vulnerable Components | Medium | Dependency pinning, regular audits (recommended) | N/A |
| A07: Identification & Authentication | High | Account lockout, MFA, password strength, token revocation | 9 |
| A08: Software & Data Integrity | Medium | JWT verification, state validation | 2 |
| A09: Logging & Monitoring | Medium | Morgan + Winston, security event logging | Verified |
| A10: Server-Side Request Forgery | Low | No external URL fetching from user input (except SSO provider URLs) | N/A |
11.2 Password Policy (OWASP-Compliant)
| Requirement | Rule | Example |
|---|---|---|
| Minimum Length | 8 characters | Password1! |
| Uppercase | At least 1 | Password1! |
| Lowercase | At least 1 | Password1! |
| Digit | At least 1 | Password1! |
| Special Character | At least 1 | Password1! |
Appendices
Appendix A: User Data Model
{
email: String (unique, indexed)
passwordHash: String (bcrypt, 12 rounds)
firstName: String
lastName: String
role: Enum ['admin', 'staff', 'viewer']
mfaEnabled: Boolean (default: false)
mfaSecret: String (TOTP secret)
mfaBackupCodes: [{ codeHash: String, used: Boolean }]
ssoProvider: String ('google' | 'microsoft')
ssoId: String (provider's user ID)
isActive: Boolean (default: true)
loginAttempts: Number (default: 0)
lockUntil: Date
lastLogin: Date
passwordChangedAt: Date
createdAt: Date (auto)
updatedAt: Date (auto)
}
Appendix B: Token Lifecycle
Appendix C: Security Event Log Examples
INFO User created: admin@afdb.org INFO MFA secret generated for user: 6a91c08b... INFO MFA backup codes generated for user: 6a91c08b... INFO MFA backup code used for user: 6a91c08b... WARN Login attempt on locked account: admin@afdb.org WARN Account locked due to 5 failed attempts: admin@afdb.org INFO SSO: auto-provisioning user for user@org.com via google INFO All tokens revoked for user: 6a91c08b... INFO Password changed for user: 6a91c08b...
Appendix D: Demo Credentials
All demo accounts use @yopmail.com email addresses. After logging in with credentials, you will receive a 6-digit OTP via email. Visit https://yopmail.com and enter the username (e.g., afdbadmin) to check the inbox and retrieve the OTP code.
| Role | Password | Yopmail Inbox | Permissions | |
|---|---|---|---|---|
| Admin | afdbadmin@yopmail.com | Admin@123 | yopmail.com/en/?afdbadmin | Full access — all features, user management, monitoring |
| Viewer | afdbaviewer@yopmail.com | Viewer@123 | yopmail.com/en/?afdbaviewer | Read-only — view dashboards, projects, reports |
| Manager | afdbmanager@yopmail.com | Manager@123 | yopmail.com/en/?afdbmanager | Project management — create, edit, approve projects (role: staff) |
AfDB Reference Application — Technical Documentation v1.0
Prepared by Eng. Depute N.Alphonse, PMP®
