mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
783 lines
29 KiB
Markdown
783 lines
29 KiB
Markdown
# STAR Phase 1 — Tier 1 Auth System
|
|
## Technical Documentation
|
|
|
|
**Version:** 1.0.0
|
|
**Author:** rgrgogu
|
|
**Date:** October 6, 2025
|
|
**Stack:** Node.js · Express · Sequelize (PostgreSQL) · JWT · Google OAuth 2.0 · Nodemailer
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Architecture Overview](#1-architecture-overview)
|
|
2. [Project Structure](#2-project-structure)
|
|
3. [Setup & Installation](#3-setup--installation)
|
|
4. [Environment Variables](#4-environment-variables)
|
|
5. [Database Models](#5-database-models)
|
|
6. [Security Layers](#6-security-layers)
|
|
7. [Authentication Flows](#7-authentication-flows)
|
|
8. [API Reference](#8-api-reference)
|
|
9. [RBAC Permission Matrix](#9-rbac-permission-matrix)
|
|
10. [File-by-File Documentation](#10-file-by-file-documentation)
|
|
11. [Error Codes Reference](#11-error-codes-reference)
|
|
12. [Extending the System](#12-extending-the-system)
|
|
|
|
---
|
|
|
|
## 1. Architecture Overview
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Client (SPA / Mobile / Browser) │
|
|
└────────────────────────────┬────────────────────────────────────┘
|
|
│ HTTPS
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Express.js App (server.js) │
|
|
│ │
|
|
│ ┌──────────┐ ┌───────────┐ ┌────────────┐ ┌────────────┐ │
|
|
│ │ CORS │ │ Rate Limit│ │ Cookie │ │ Session │ │
|
|
│ │ Guard │ │ (global) │ │ Parser │ │ (csurf) │ │
|
|
│ └──────────┘ └───────────┘ └────────────┘ └────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
│ │ Routes │ │
|
|
│ │ /api/auth/* → auth.routes.js │ │
|
|
│ │ /api/client/* → client.routes.js │ │
|
|
│ │ /api/staff/users/*→ staff.routes.js │ │
|
|
│ │ /api/admin/* → admin.routes.js │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
│ │ Middleware Chain (per-route) │ │
|
|
│ │ authLimiter → csrfProtection → validate → authenticate │ │
|
|
│ │ → requireRole() → Controller │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
│ │ Services │ Utils │ │
|
|
│ │ email.service.js │ token.util.js │ │
|
|
│ │ │ otp.util.js │ │
|
|
│ │ │ response.util.js │ │
|
|
│ └──────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────┬───────────────────────┘
|
|
│ Sequelize ORM
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ PostgreSQL │
|
|
│ ┌──────────┐ ┌─────────────────┐ ┌──────────────────────┐ │
|
|
│ │ users │ │ user_sessions │ │ user_groups / │ │
|
|
│ │ │ │ │ │ user_group_members │ │
|
|
│ └──────────┘ └─────────────────┘ └──────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Project Structure
|
|
|
|
```
|
|
new_starr/
|
|
├── server.js ← App entry point
|
|
├── package.json
|
|
├── .env.example ← Copy to .env and fill values
|
|
│
|
|
├── config/
|
|
│ ├── db.config.js ← Sequelize PostgreSQL instance
|
|
│ └── passport.config.js ← Google OAuth 2.0 strategy
|
|
│
|
|
├── models/
|
|
│ ├── users.mdl.js ← Users table (with OTP fields)
|
|
│ ├── user_sessions.mdl.js ← Session audit table
|
|
│ └── user_groups.mdl.js ← Groups + Junction table
|
|
│
|
|
├── middleware/
|
|
│ ├── auth.middleware.js ← JWT Bearer token verification
|
|
│ ├── rbac.middleware.js ← Role-based access guards
|
|
│ ├── csrf.middleware.js ← CSRF protection (csurf)
|
|
│ ├── rateLimiter.middleware.js ← Per-route rate limits
|
|
│ └── validate.middleware.js ← express-validator result handler
|
|
│
|
|
├── validators/
|
|
│ ├── auth.validator.js ← register / login / OTP / password rules
|
|
│ └── profile.validator.js ← profile update rules
|
|
│
|
|
├── controllers/
|
|
│ ├── auth.controller.js ← Shared: register, OTP, login, refresh, logout
|
|
│ ├── client/
|
|
│ │ └── profile.controller.js ← Own profile + own sessions
|
|
│ ├── staff/
|
|
│ │ └── users.controller.js ← View/toggle non-admin users
|
|
│ └── admin/
|
|
│ └── users.controller.js ← Full CRUD + groups
|
|
│
|
|
├── routes/
|
|
│ ├── auth.routes.js ← /api/auth/*
|
|
│ ├── client/
|
|
│ │ └── client.routes.js ← /api/client/*
|
|
│ ├── staff/
|
|
│ │ └── staff.routes.js ← /api/staff/users/*
|
|
│ └── admin/
|
|
│ └── admin.routes.js ← /api/admin/*
|
|
│
|
|
├── services/
|
|
│ └── email.service.js ← Nodemailer OTP + welcome emails
|
|
│
|
|
└── utils/
|
|
├── token.util.js ← JWT generate / verify / hash
|
|
├── otp.util.js ← OTP generate / expiry / check
|
|
└── response.util.js ← Standardised JSON responses
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Setup & Installation
|
|
|
|
```bash
|
|
# 1. Clone / copy the project
|
|
cd star-auth-system
|
|
|
|
# 2. Install dependencies
|
|
npm install
|
|
|
|
# 3. Configure environment
|
|
cp .env.example .env
|
|
# Edit .env with your DB, SMTP, Google OAuth, and JWT credentials
|
|
|
|
# 4. Ensure PostgreSQL is running and the DB exists
|
|
createdb star_db
|
|
|
|
# 5. Start development server (auto-syncs models)
|
|
npm run dev
|
|
|
|
# 6. Production
|
|
npm start
|
|
```
|
|
|
|
> **Note:** On first boot, Sequelize will create all tables automatically via `sequelize.sync({ alter: true })`.
|
|
|
|
---
|
|
|
|
## 4. Environment Variables
|
|
|
|
| Variable | Description | Example |
|
|
|---|---|---|
|
|
| `APP_NAME` | Application name | `starr` |
|
|
| `NODE_ENV` | `development` or `production` | `development` |
|
|
| `ORIGIN_GUARD_DISABLED` | Set `true` to bypass originGuard (dev/Postman only; ignored in production) | `false` |
|
|
| `PORT` | HTTP port | `3000` |
|
|
| `APP_URL` | Frontend/app URL (used for CORS) | `http://localhost:3000` |
|
|
| `DB_HOST` | PostgreSQL host | `localhost` |
|
|
| `DB_PORT` | PostgreSQL port | `5432` |
|
|
| `DB_NAME` | Database name | `star_db` |
|
|
| `DB_USER` | DB user | `postgres` |
|
|
| `DB_PASSWORD` | DB password | `yourpassword` |
|
|
| `JWT_SECRET` | Access token signing key (≥32 chars) | `your_super_secret_…` |
|
|
| `JWT_EXPIRES_IN` | Access token TTL | `1d` |
|
|
| `JWT_REFRESH_SECRET` | Refresh token signing key | `your_refresh_secret_…` |
|
|
| `JWT_REFRESH_EXPIRES_IN` | Refresh token TTL | `7d` |
|
|
| `SESSION_SECRET` | Express session secret (used by csurf) | `your_session_secret_…` |
|
|
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | from GCP Console |
|
|
| `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | from GCP Console |
|
|
| `GOOGLE_CALLBACK_URL` | OAuth redirect URI | `/api/auth/google/callback` |
|
|
| `SMTP_HOST` | Mail server host | `smtp.gmail.com` |
|
|
| `SMTP_PORT` | Mail server port | `587` |
|
|
| `SMTP_USER` | Mail username | `you@gmail.com` |
|
|
| `SMTP_PASS` | Mail password / App Password | `xxxx xxxx xxxx xxxx` |
|
|
| `EMAIL_FROM` | Sender address | `no-reply@star-system.com` |
|
|
| `OTP_EXPIRY_MINUTES` | OTP validity in minutes | `10` |
|
|
|
|
---
|
|
|
|
## 5. Database Models
|
|
|
|
### 5.1 `users` Table
|
|
|
|
| Column | Type | Notes |
|
|
|---|---|---|
|
|
| `user_id` | BIGINT PK | Auto-increment |
|
|
| `email` | VARCHAR(255) UNIQUE | Validated email |
|
|
| `password` | TEXT | bcrypt hash (null for Google users) |
|
|
| `is_active` | BOOLEAN | Default `true` |
|
|
| `is_verified` | BOOLEAN | Default `false`; set `true` on OTP verify |
|
|
| `reg_type` | ENUM | `system` or `google` |
|
|
| `acc_type` | ENUM | `user` / `staff` / `admin` |
|
|
| `personal_info` | JSONB | Nested name, addresses, phone, avatar, album |
|
|
| `otp_code` | VARCHAR(6) | Cleared after verification |
|
|
| `otp_expires_at` | TIMESTAMP | Cleared after verification |
|
|
| `createdAt` | TIMESTAMP | Auto |
|
|
| `updatedAt` | TIMESTAMP | Auto |
|
|
|
|
### 5.2 `user_sessions` Table
|
|
|
|
| Column | Type | Notes |
|
|
|---|---|---|
|
|
| `session_id` | BIGINT PK | Auto-increment |
|
|
| `user_id` | BIGINT FK | → users.user_id |
|
|
| `login_info` | JSONB | `{ date, ip_address, device_info }` |
|
|
| `logout_info` | JSONB | Populated on logout |
|
|
| `refresh_token_hash` | TEXT | SHA-256 of refresh token |
|
|
| `is_active` | BOOLEAN | `false` after logout |
|
|
|
|
### 5.3 `user_groups` + `user_group_members` Tables
|
|
|
|
Groups are named permission bundles. A user can belong to multiple groups.
|
|
|
|
```
|
|
users ──< user_group_members >── user_groups
|
|
(user_id, group_id,
|
|
joined_at)
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Security Layers
|
|
|
|
### 6.1 Rate Limiting
|
|
|
|
| Limiter | Routes | Window | Max |
|
|
|---|---|---|---|
|
|
| `globalLimiter` | All routes | 15 min | 1 000 |
|
|
| `authLimiter` | `/register`, `/login` | 15 min | 20 |
|
|
| `otpLimiter` | `/verify-otp`, `/resend-otp` | 15 min | 5 |
|
|
| `sensitiveOpsLimiter` | `/change-password` | 60 min | 10 |
|
|
|
|
### 6.2 CSRF Protection
|
|
|
|
CSRF is provided via **csurf** (Double Submit Cookie pattern).
|
|
|
|
- Retrieve token: `GET /api/auth/csrf-token`
|
|
- Send token: `X-CSRF-Token` header OR `_csrf` body field
|
|
- Applied automatically to cookie-based flows
|
|
|
|
> **SPA / REST API clients using `Authorization: Bearer` are inherently CSRF-safe** because cross-site requests cannot set custom headers. CSRF is included for hybrid/SSR scenarios.
|
|
|
|
### 6.3 JWT Authentication
|
|
|
|
- **Access Token:** Short-lived (1 day). Sent as `Authorization: Bearer <token>`.
|
|
- **Refresh Token:** Long-lived (7 days). SHA-256 hash stored in `user_sessions`. Rotated on every `/refresh` call.
|
|
- **Session invalidation:** Logout, password change, and admin force-terminate all flip `is_active = false`.
|
|
|
|
### 6.4 Password Security
|
|
|
|
- bcryptjs with **cost factor 12**
|
|
- Minimum 8 chars, must contain uppercase + digit
|
|
- Current password required before change
|
|
- All sessions invalidated after password change
|
|
|
|
### 6.5 Origin Guard
|
|
|
|
All API routes (except `/api/health`) are protected by `originGuard.middleware.js`, a two-layer non-browser request filter:
|
|
|
|
| Layer | Header checked | Applies to | Blocks |
|
|
|---|---|---|---|
|
|
| 1 | `Sec-Fetch-Site` (must be present) | All methods | curl, Postman, Nikto, sqlmap, scanners |
|
|
| 2 | `Origin` (must be in `ALLOWED_ORIGINS`) | POST · PUT · PATCH · DELETE | Cross-origin mutation from unlisted domains |
|
|
|
|
**Development bypass** — set `ORIGIN_GUARD_DISABLED=true` in `.env` to allow Postman and other tools through without restarting with a different config. The bypass is **hard-locked off** when `NODE_ENV=production`, even if the flag is set.
|
|
|
|
```
|
|
# .env — enable for Postman testing
|
|
ORIGIN_GUARD_DISABLED=true
|
|
|
|
# .env — re-enable when done
|
|
ORIGIN_GUARD_DISABLED=false
|
|
```
|
|
|
|
> Note: BurpSuite running as a MITM proxy through a real browser is not blocked — the browser supplies all correct headers. Rate limiting and valid credentials are the only defences there.
|
|
|
|
---
|
|
|
|
### 6.6 RBAC Hierarchy
|
|
|
|
```
|
|
admin ──► can do everything
|
|
│
|
|
staff ──► can view/toggle client+staff users; cannot touch admin accounts
|
|
│
|
|
user ──► can only manage own profile and sessions
|
|
(client)
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Authentication Flows
|
|
|
|
### 7.1 System Registration → OTP Verify → Auto-Login
|
|
|
|
```
|
|
Client Server Email
|
|
│ │ │
|
|
│── POST /api/auth/register ──► │ │
|
|
│ { email, password } │ │
|
|
│ │── create user (unverified)│
|
|
│ │── generate OTP ──────────►│
|
|
│◄── 201 { email } ─────────── │ │
|
|
│ │ │
|
|
│── POST /api/auth/verify-otp ►│ │
|
|
│ { email, otp } │ │
|
|
│ │── validate OTP │
|
|
│ │── mark is_verified=true │
|
|
│ │── create session record │
|
|
│ │── send welcome email ────►│
|
|
│◄── 200 { accessToken, │ │
|
|
│ refreshToken, │ │
|
|
│ user } ─────────── │ │
|
|
```
|
|
|
|
### 7.2 System Login
|
|
|
|
```
|
|
Client Server
|
|
│── POST /api/auth/login ─────►│
|
|
│ { email, password } │
|
|
│ │── lookup user by email
|
|
│ │── bcrypt.compare(password, hash)
|
|
│ │── create session record
|
|
│◄── 200 { accessToken, │
|
|
│ refreshToken, │
|
|
│ session_id, user } ──│
|
|
```
|
|
|
|
### 7.3 Google OAuth
|
|
|
|
```
|
|
Client Google Server
|
|
│── GET /api/auth/google ──────────────►│
|
|
│ │── redirect to Google
|
|
│◄─────── Google consent screen ───────│
|
|
│── approve ──►[Google] ───callback──► │
|
|
│ │── find or create user
|
|
│ │── create session
|
|
│◄── 200 { accessToken, refreshToken } ─│
|
|
```
|
|
|
|
### 7.4 Token Refresh
|
|
|
|
```
|
|
Client Server
|
|
│── POST /api/auth/refresh ───►│
|
|
│ { refreshToken } │
|
|
│ │── verify JWT signature
|
|
│ │── lookup session by token hash
|
|
│ │── rotate refresh token
|
|
│◄── 200 { accessToken, │
|
|
│ refreshToken } ─────│
|
|
```
|
|
|
|
### 7.5 Logout
|
|
|
|
```
|
|
Client Server
|
|
│── POST /api/auth/logout ────►│
|
|
│ Authorization: Bearer ... │
|
|
│ { session_id } │
|
|
│ │── authenticate JWT
|
|
│ │── set session.is_active=false
|
|
│ │── save logout_info
|
|
│◄── 200 "Logged out" ─────── │
|
|
```
|
|
|
|
---
|
|
|
|
## 8. API Reference
|
|
|
|
> **Base URL:** `http://localhost:3000/api`
|
|
> **Auth header:** `Authorization: Bearer <accessToken>`
|
|
|
|
---
|
|
|
|
### 8.1 Auth Endpoints (Public)
|
|
|
|
#### `POST /auth/register`
|
|
Register a new client account.
|
|
|
|
**Request body:**
|
|
```json
|
|
{
|
|
"email": "jane@example.com",
|
|
"password": "Password1"
|
|
}
|
|
```
|
|
|
|
**Response 201:**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Registration successful. Please check your email for the OTP.",
|
|
"data": { "email": "jane@example.com" }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `POST /auth/verify-otp`
|
|
Verify email with OTP. Returns tokens (auto-login).
|
|
|
|
**Request body:**
|
|
```json
|
|
{ "email": "jane@example.com", "otp": "048291" }
|
|
```
|
|
|
|
**Response 200:**
|
|
```json
|
|
{
|
|
"status": "success",
|
|
"message": "Email verified successfully. You are now logged in.",
|
|
"data": {
|
|
"accessToken": "eyJ...",
|
|
"refreshToken": "eyJ...",
|
|
"session_id": 1,
|
|
"user": { "user_id": 1, "email": "jane@example.com", "acc_type": "user", ... }
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `POST /auth/resend-otp`
|
|
Resend OTP email (5 requests / 15 min limit).
|
|
|
|
**Request body:** `{ "email": "jane@example.com" }`
|
|
|
|
---
|
|
|
|
#### `POST /auth/login`
|
|
System (email + password) login.
|
|
|
|
**Request body:**
|
|
```json
|
|
{ "email": "jane@example.com", "password": "Password1" }
|
|
```
|
|
|
|
**Response 200:** Same shape as verify-otp.
|
|
|
|
---
|
|
|
|
#### `POST /auth/refresh`
|
|
Rotate access + refresh tokens.
|
|
|
|
**Request body:** `{ "refreshToken": "eyJ..." }`
|
|
|
|
---
|
|
|
|
#### `GET /auth/google`
|
|
Redirect to Google consent screen. No body needed.
|
|
|
|
---
|
|
|
|
#### `GET /auth/google/callback`
|
|
Google OAuth redirect target. Returns tokens on success.
|
|
|
|
---
|
|
|
|
#### `POST /auth/logout` *(requires Bearer token)*
|
|
Invalidates the specified session.
|
|
|
|
**Request body:** `{ "session_id": 1 }`
|
|
|
|
---
|
|
|
|
#### `POST /auth/change-password` *(requires Bearer token)*
|
|
Change password. Invalidates all sessions.
|
|
|
|
**Request body:**
|
|
```json
|
|
{ "current_password": "OldPass1", "new_password": "NewPass2" }
|
|
```
|
|
|
|
---
|
|
|
|
### 8.2 Client Endpoints *(requires Bearer — any acc_type)*
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| GET | `/client/profile` | Own profile |
|
|
| PUT | `/client/profile` | Update own `personal_info` |
|
|
| GET | `/client/sessions` | Own active sessions |
|
|
| DELETE | `/client/sessions/:id` | Revoke one of own sessions |
|
|
|
|
**PUT /client/profile — Example body:**
|
|
```json
|
|
{
|
|
"personal_info": {
|
|
"name": {
|
|
"given_name": "Jane",
|
|
"last_name": "Doe"
|
|
},
|
|
"occupation": "Engineer",
|
|
"date_of_birth": "1995-06-15"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 8.3 Staff Endpoints *(requires Bearer — staff or admin)*
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| GET | `/staff/users` | Paginated list (non-admins) |
|
|
| GET | `/staff/users/:id` | Single non-admin user |
|
|
| PUT | `/staff/users/:id/status` | Toggle `is_active` |
|
|
| GET | `/staff/users/:id/sessions` | User's sessions |
|
|
|
|
**Query params for GET list:** `?page=1&limit=20`
|
|
|
|
**PUT /staff/users/:id/status — Body:** `{ "is_active": false }`
|
|
|
|
---
|
|
|
|
### 8.4 Admin Endpoints *(requires Bearer — admin only)*
|
|
|
|
| Method | Path | Description |
|
|
|---|---|---|
|
|
| GET | `/admin/users` | All users (paginated) |
|
|
| GET | `/admin/users/:id` | Any user with groups |
|
|
| PUT | `/admin/users/:id` | Update `acc_type`, `is_active`, `personal_info` |
|
|
| DELETE | `/admin/users/:id` | Hard delete user |
|
|
| GET | `/admin/users/:id/sessions` | All sessions |
|
|
| DELETE | `/admin/users/:id/sessions/:sid` | Force-terminate session |
|
|
| GET | `/admin/groups` | List all groups |
|
|
| POST | `/admin/groups` | Create group `{ name, description }` |
|
|
| DELETE | `/admin/groups/:gid` | Delete group |
|
|
| POST | `/admin/users/:id/groups/:gid` | Add user to group |
|
|
| DELETE | `/admin/users/:id/groups/:gid` | Remove user from group |
|
|
|
|
**PUT /admin/users/:id — Allowed fields:**
|
|
```json
|
|
{
|
|
"acc_type": "staff",
|
|
"is_active": true,
|
|
"personal_info": { ... }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 9. RBAC Permission Matrix
|
|
|
|
| Action | Client (`user`) | Staff (`staff`) | Admin (`admin`) |
|
|
|---|:---:|:---:|:---:|
|
|
| Register | ✅ | ✅ | ✅ |
|
|
| Login | ✅ | ✅ | ✅ |
|
|
| View own profile | ✅ | ✅ | ✅ |
|
|
| Edit own profile | ✅ | ✅ | ✅ |
|
|
| View own sessions | ✅ | ✅ | ✅ |
|
|
| Revoke own session | ✅ | ✅ | ✅ |
|
|
| Change own password | ✅ | ✅ | ✅ |
|
|
| List all users | ❌ | ✅ (no admins) | ✅ |
|
|
| View any user | ❌ | ✅ (no admins) | ✅ |
|
|
| Toggle user status | ❌ | ✅ (no admins) | ✅ |
|
|
| View user sessions | ❌ | ✅ (no admins) | ✅ |
|
|
| Change user `acc_type` | ❌ | ❌ | ✅ |
|
|
| View admin accounts | ❌ | ❌ | ✅ |
|
|
| Hard delete users | ❌ | ❌ | ✅ |
|
|
| Force-terminate session | ❌ | ❌ | ✅ |
|
|
| Manage groups | ❌ | ❌ | ✅ |
|
|
|
|
---
|
|
|
|
## 10. File-by-File Documentation
|
|
|
|
### `server.js`
|
|
**Purpose:** Application entry point. Bootstraps Express, registers global middleware (CORS, rate limiter, cookie-parser, session, Passport), mounts all routes, syncs DB models.
|
|
**Key behaviors:**
|
|
- Runs `sequelize.sync({ alter: true })` on startup (development) — safe column updates.
|
|
- Registers a global 404 handler and error handler.
|
|
- Enables `trust proxy` for correct IP detection behind load balancers.
|
|
|
|
---
|
|
|
|
### `config/db.config.js`
|
|
**Purpose:** Creates and exports a single authenticated Sequelize instance.
|
|
**Usage:** `const sequelize = require('./config/db.config');`
|
|
|
|
---
|
|
|
|
### `config/passport.config.js`
|
|
**Purpose:** Registers the Google OAuth 2.0 strategy. Auto-creates user on first Google login with `reg_type='google'` and `is_verified=true`.
|
|
**Usage:** Imported in `server.js`; used in `routes/auth.routes.js` via `passport.authenticate('google', ...)`.
|
|
|
|
---
|
|
|
|
### `models/users.mdl.js`
|
|
**Purpose:** Defines the `users` table including OTP fields (`otp_code`, `otp_expires_at`) added for the verification flow.
|
|
**Exported as:** `mdl_Users` (default)
|
|
|
|
---
|
|
|
|
### `models/user_sessions.mdl.js`
|
|
**Purpose:** Audit log for logins/logouts. Stores `refresh_token_hash` for secure token rotation and session invalidation. Sets up `belongsTo/hasMany` with Users.
|
|
**Exported as:** `mdl_UserSessions` (default)
|
|
|
|
---
|
|
|
|
### `models/user_groups.mdl.js`
|
|
**Purpose:** `user_groups` and `user_group_members` junction table. Implements `belongsToMany` associations between Users and Groups.
|
|
**Exported as:** `{ mdl_UserGroups, mdl_UserGroupMembers }`
|
|
|
|
---
|
|
|
|
### `middleware/auth.middleware.js`
|
|
**Purpose:** Reads `Authorization: Bearer <token>`, calls `verifyAccessToken()`, loads the user from DB, and attaches it to `req.user`.
|
|
**Exported:** `authenticate`
|
|
|
|
---
|
|
|
|
### `middleware/rbac.middleware.js`
|
|
**Purpose:** Role guards that inspect `req.user.acc_type`. All guards must be used **after** `authenticate`.
|
|
**Exported:** `requireClient()`, `requireStaff()`, `requireAdmin()`, `requireOwnerOrStaff()`, `requireOwnerOrAdmin()`
|
|
|
|
---
|
|
|
|
### `middleware/csrf.middleware.js`
|
|
**Purpose:** Wraps `csurf` with a token endpoint and a dedicated error handler.
|
|
**Exported:** `csrfProtection`, `getCsrfToken`, `csrfErrorHandler`
|
|
|
|
---
|
|
|
|
### `middleware/rateLimiter.middleware.js`
|
|
**Purpose:** Four rate-limiter configurations for different route tiers.
|
|
**Exported:** `globalLimiter`, `authLimiter`, `otpLimiter`, `sensitiveOpsLimiter`
|
|
|
|
---
|
|
|
|
### `middleware/validate.middleware.js`
|
|
**Purpose:** Reads the `validationResult` from express-validator and returns 422 if any rule failed.
|
|
**Exported:** `validate`
|
|
|
|
---
|
|
|
|
### `validators/auth.validator.js`
|
|
**Purpose:** express-validator chains for `register`, `login`, `verify-otp`, `resend-otp`, `change-password`.
|
|
**Usage:** Spread into route definitions: `router.post('/login', ...loginValidator, validate, handler)`
|
|
|
|
---
|
|
|
|
### `validators/profile.validator.js`
|
|
**Purpose:** Validates `personal_info` fields on profile update requests.
|
|
|
|
---
|
|
|
|
### `utils/token.util.js`
|
|
**Purpose:** JWT helpers.
|
|
**Functions:**
|
|
- `generateTokens(user)` → `{ accessToken, refreshToken }`
|
|
- `verifyAccessToken(token)` → decoded payload (throws on expiry/invalid)
|
|
- `verifyRefreshToken(token)` → decoded payload
|
|
- `hashToken(token)` → SHA-256 hex string for DB storage
|
|
|
|
---
|
|
|
|
### `utils/otp.util.js`
|
|
**Purpose:** Cryptographically secure OTP helpers.
|
|
**Functions:**
|
|
- `generateOTP()` → `"048291"` (6 digits, padded)
|
|
- `getOTPExpiry(minutes)` → `Date` N minutes from now
|
|
- `isOTPExpired(expiresAt)` → `boolean`
|
|
|
|
---
|
|
|
|
### `utils/response.util.js`
|
|
**Purpose:** Standardised response envelope `{ status, message, data?, errors? }`.
|
|
**Functions:** `success(res, msg, data, statusCode)`, `error(res, msg, statusCode, errors)`, `validationError(res, errors)`
|
|
|
|
---
|
|
|
|
### `services/email.service.js`
|
|
**Purpose:** Nodemailer transporter with two email templates.
|
|
**Functions:**
|
|
- `sendOTPEmail(to, otp, expiryMinutes)` — styled HTML OTP email
|
|
- `sendWelcomeEmail(to, name)` — post-verification welcome
|
|
|
|
---
|
|
|
|
### `controllers/auth.controller.js`
|
|
**Purpose:** Shared auth logic: `register`, `verifyOTP`, `resendOTP`, `login`, `googleCallback`, `refreshToken`, `logout`, `changePassword`.
|
|
|
|
---
|
|
|
|
### `controllers/client/profile.controller.js`
|
|
**Purpose:** Self-service profile actions for any authenticated user.
|
|
**Functions:** `getProfile`, `updateProfile` (deep-merge), `getSessions`, `revokeSession`
|
|
|
|
---
|
|
|
|
### `controllers/staff/users.controller.js`
|
|
**Purpose:** Staff-level user management (read-only + status toggle; no admin data).
|
|
**Functions:** `getUsers`, `getUser`, `setUserStatus`, `getUserSessions`
|
|
|
|
---
|
|
|
|
### `controllers/admin/users.controller.js`
|
|
**Purpose:** Full admin control over users, sessions, and groups.
|
|
**Functions:** `getUsers`, `getUser`, `updateUser`, `deleteUser`, `getUserSessions`, `terminateSession`, `getGroups`, `createGroup`, `deleteGroup`, `addUserToGroup`, `removeUserFromGroup`
|
|
|
|
---
|
|
|
|
## 11. Error Codes Reference
|
|
|
|
| HTTP | Scenario |
|
|
|---|---|
|
|
| 400 | Bad request (missing field, wrong type, already verified) |
|
|
| 401 | Missing/invalid/expired token, wrong credentials |
|
|
| 403 | Account deactivated, wrong role, CSRF error |
|
|
| 404 | Resource not found |
|
|
| 409 | Email already registered |
|
|
| 422 | Validation failed (see `errors[]` array) |
|
|
| 429 | Rate limit exceeded |
|
|
| 500 | Internal server error |
|
|
|
|
All error responses follow:
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"message": "Human-readable reason",
|
|
"errors": [ ... ] // only on 422
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Extending the System
|
|
|
|
### Add a New Endpoint
|
|
|
|
1. Create validator rules in `validators/`
|
|
2. Create or extend a controller in `controllers/<role>/`
|
|
3. Add the route in `routes/<role>/<role>.routes.js` with appropriate middleware chain
|
|
4. No changes to `server.js` needed if mounting the same base path
|
|
|
|
### Add a New Role
|
|
|
|
1. Add the ENUM value to `acc_type` in `users.mdl.js`
|
|
2. Add a guard in `rbac.middleware.js` (e.g., `requireSuperAdmin()`)
|
|
3. Create a dedicated route + controller folder
|
|
|
|
### Add Redis Session Store
|
|
|
|
Install `connect-redis` and update `server.js`:
|
|
```js
|
|
const RedisStore = require('connect-redis').default;
|
|
const { createClient } = require('redis');
|
|
const redisClient = createClient({ url: process.env.REDIS_URL });
|
|
await redisClient.connect();
|
|
app.use(session({ store: new RedisStore({ client: redisClient }), ... }));
|
|
```
|
|
|
|
### Production Checklist
|
|
|
|
- [ ] Set `NODE_ENV=production`
|
|
- [ ] Set `ORIGIN_GUARD_DISABLED=false` (or remove the key entirely)
|
|
- [ ] Use strong `JWT_SECRET` (≥ 64 random characters)
|
|
- [ ] Enable HTTPS / TLS (set `cookie.secure: true`)
|
|
- [ ] Point `APP_URL` to your actual domain for CORS
|
|
- [ ] Replace in-memory rate limiter with Redis store
|
|
- [ ] Set up log rotation (replace `console.log` with Winston/Pino)
|
|
- [ ] Use `sequelize.sync({ force: false, alter: false })` in production (run migrations instead)
|
|
|
|
---
|
|
|
|
*End of Documentation — STAR Phase 1 Auth System v1.0.0* |