Skip to content

Backend Middleware

The backend uses Nitro's middleware system to enforce security, logging, and operational logic globally. Middleware files are located in apps/backend-api/src/middleware/ and are executed in numeric/alphabetical order.

Middleware Execution Pipeline

The numbers in the filenames dictate the execution order. This hierarchy is critical for security:

  1. 0.5.correlation.ts: Tracing setup.
  2. 0.maintenance.ts: Global kill-switch.
  3. 1.logger.ts: Request logging.
  4. 2.auth.ts: Authentication & RBAC.
  5. 2.5.csrf.ts: CSRF Protection.
  6. 3.ratelimit.ts: Rate Limiting.

1. Correlation & Tracing (0.5.correlation.ts)

Purpose: Assigns a unique ID to every request to track it across logs and services.

  • Logic:
    1. Checks for an existing ID in headers X-Correlation-ID or X-Request-ID (useful for microservices).
    2. If missing, generates a new UUID.
    3. Attaches the ID to the event.context.
    4. Sets the X-Correlation-ID header on the response.

2. Maintenance Mode (0.maintenance.ts)

Purpose: Allows administrators to lock the system for upgrades while keeping it accessible to themselves.

  • Config Key: maintenance_mode (in SystemConfig table).
  • Logic:
    1. Exclusions: Skips /api/health and /api/status so monitoring tools don't alert false positives.
    2. Checks the global maintenance_mode setting.
    3. If Enabled:
      • Verifies the user's authentication.
      • Bypass: Allows the request if the user has the super role.
      • Block: Returns 503 Service Unavailable for all other users.

3. Operation Logging (1.logger.ts)

Purpose: Records a detailed audit trail of all API interactions.

  • Data Source: Reads from event.context populated by other middleware (User, Correlation ID, Old/New Values).
  • Storage: Writes to the OperationLog database table.
  • Logic:
    1. Exclusions: Skips /health, /test, and /uploads/ to reduce noise.
    2. Hooks into the response finish event to capture the final HTTP status code and duration.
    3. Records: User, IP, Path, Method, Params, and Duration.
    4. Context: Can capture operationDescription, oldValue, and newValue if set by route handlers.

4. Authentication & RBAC (2.auth.ts)

Purpose: The central security gatekeeper. Handles Identity (Who are you?) and Permissions (Can you do this?).

  • Logic:
    1. Public Paths: Skips validation for Login, Refresh, MFA, and Health checks.
    2. Authentication (AuthN):
      • Validates the JWT Access Token.
      • Session Check: Verifies against the UserSession table to ensure the session hasn't been revoked or expired.
      • Updates the session's lastActiveAt timestamp.
    3. Authorization (AuthZ):
      • Super Admin: Bypasses all permission checks.
      • Route Matching: Matches the request path (/api/users) to an ApiPermission record in the database.
      • Permission Check: Verifies if the user's Role is linked to that ApiPermission.
      • Caching: Uses Valkey (Redis) to cache permission lookups for performance (perms:role:...).
    4. Result:
      • 401 Unauthorized if invalid token/session.
      • 403 Forbidden if role doesn't have permission.

5. CSRF Protection (2.5.csrf.ts)

Purpose: Prevents Cross-Site Request Forgery attacks using the Double-Submit Cookie pattern.

  • Pattern: Requires both a cookie (XSRF-TOKEN) and a matching header (X-XSRF-TOKEN).
  • Logic:
    1. Exclusions:
      • Safe Methods: GET, HEAD, OPTIONS.
      • Public Paths: Login, Refresh, MFA.
      • Uploads: /uploads/ (handled via other means).
    2. Reads the token from the Cookie and the Request Header.
    3. Validation:
      • Both must exist.
      • Both must match exactly.
    4. Result: 403 Forbidden on mismatch.

6. Rate Limiting (3.ratelimit.ts)

Purpose: Protects the API from abuse, brute-force attacks, and DoS attempts.

  • Storage: Uses the RateLimit table (PostgreSQL).
  • Rules:
    • Auth Endpoints: 100 requests / 15 mins (Strict).
    • User Creation: 50 requests / 1 hour (Anti-spam).
    • Password Reset: 5 requests / 1 hour (High security).
    • File Uploads: 100 requests / 1 hour.
    • General API: 60 requests / 1 minute.
  • Logic:
    1. Identifies the rule based on the request path.
    2. Atomic Counting: Performs a database Upsert (Insert or Update) to increment the counter for the IP address.
    3. Enforcement:
      • If count > limit, returns 429 Too Many Requests.
      • Returns a Retry-After message.