auth.md 5.3 KB

Authentication & Authorization

This document describes the authentication and authorization model for the internal delivery note browser.

The system uses:

  • MongoDB to store users (via Mongoose models).
  • Cookie-based sessions with a signed JWT payload.
  • Role-aware access control (branch, admin, dev).
  • Branch-level RBAC enforcement for filesystem-related APIs.

NOTE: This document is a living document. As we extend the auth system (sessions, routes, policies, password flows), we will update this file.


1. Goals & Scope

The main goals of the authentication and authorization system are:

  • Only authenticated users can access protected backend APIs.
  • Branch users can only see delivery notes for their own branch.
  • Admin and dev users can access data across branches.
  • Passwords are never stored in plaintext.
  • Sessions are stored as signed JWTs in HTTP-only cookies.

This document covers:

  • Environment variables related to auth.
  • Roles and RBAC rules.
  • Session payload and cookie configuration.
  • Login and logout endpoints.

2. Environment & Configuration

2.1 Required variables

Auth depends on the following environment variables:

  • SESSION_SECRET (required)

    • Strong, random string used to sign and verify JWT session tokens.
    • Minimum length: 32 characters.
    • Must be kept secret.
    • Should differ between environments (dev/staging/prod).

Auth endpoints also require DB connectivity:

  • MONGODB_URI (required)

2.2 Optional variables

  • SESSION_COOKIE_SECURE (optional)

    • Overrides the Secure cookie flag.
    • Allowed values: true or false.

Default behavior:

  • Secure cookie is enabled when NODE_ENV === "production".

Local HTTP testing (e.g. http://localhost:3000 with Docker + next start):

  • Set SESSION_COOKIE_SECURE=false in your local .env.docker.

Staging/Production:

  • Keep SESSION_COOKIE_SECURE unset (or true) and run the app behind HTTPS.

2.3 Fail-fast environment validation

The repo provides centralized env validation:

  • lib/config/validateEnv.js validates required env vars and basic sanity checks.
  • scripts/validate-env.mjs runs validation against process.env.

In Docker, run validation before starting the server:

node scripts/validate-env.mjs && npm run start

3. Roles

3.1 branch

  • Represents a user who belongs to a specific branch/location.
  • Must have a valid branchId (e.g. "NL01").
  • Intended access pattern:

    • Can only access delivery notes for their own branch.
    • Cannot access other branches.

3.2 admin

  • Administrator account.
  • Typically not bound to any single branch (branchId = null).
  • Intended access pattern:

    • Can access delivery notes across all branches.

3.3 dev

  • Development/engineering account.
  • Typically not bound to any single branch (branchId = null).
  • Intended access pattern:

    • Full or near-full access.

4. Authorization: Branch-Level RBAC

RBAC is enforced on branch-related filesystem APIs.

4.1 Response semantics

  • 401 Unauthorized: no valid session (getSession() returns null).

    { "error": "Unauthorized" }
    
  • 403 Forbidden: session exists but the user is not allowed to access the requested branch.

    { "error": "Forbidden" }
    

4.2 Permission helpers

RBAC rules live in lib/auth/permissions.js:

  • canAccessBranch(session, branchId)
  • filterBranchesForSession(session, branchIds)

4.3 Protected endpoints

These endpoints require a valid session:

  • GET /api/branches
  • GET /api/branches/[branch]/years
  • GET /api/branches/[branch]/[year]/months
  • GET /api/branches/[branch]/[year]/[month]/days
  • GET /api/files?branch=&year=&month=&day=

5. Sessions & Cookies

Sessions are implemented as signed JWTs stored in HTTP-only cookies.

5.1 Session payload

{
	"userId": "<MongoDB ObjectId as string>",
	"role": "branch | admin | dev",
	"branchId": "NL01 | null",
	"iat": 1700000000,
	"exp": 1700003600
}

5.2 JWT signing

  • Algorithm: HS256.
  • Secret: SESSION_SECRET.
  • Token lifetime: SESSION_MAX_AGE_SECONDS = 8 hours.

5.3 Cookie settings

Cookie name: auth_session

Attributes:

  • httpOnly: true
  • secure: resolved via NODE_ENV + optional SESSION_COOKIE_SECURE override
  • sameSite: "lax"
  • path: "/"
  • maxAge: 8 hours

Implementation lives in lib/auth/session.js:

  • createSession({ userId, role, branchId })
  • getSession()
  • destroySession()

6. Core Auth Endpoints

6.1 POST /api/auth/login

Authenticate a user and set the session cookie.

Responses:

  • 200 { "ok": true }
  • 400 { "error": "Invalid request body" }
  • 400 { "error": "Missing username or password" }
  • 401 { "error": "Invalid credentials" }
  • 500 { "error": "Internal server error" }

6.2 GET /api/auth/logout

Clears the session cookie.

  • Returns 200 { "ok": true } on success.
  • Logout is idempotent.

7. Security Notes

  • Use HTTPS for real users (staging/prod).
  • Keep SESSION_SECRET secret and rotate when needed.
  • Local HTTP testing is supported via SESSION_COOKIE_SECURE=false.