# 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 in 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: ```sh 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 Error responses use the standardized API error payload: ```json { "error": { "message": "Human readable message", "code": "SOME_MACHINE_CODE", "details": {} } } ``` - **401 Unauthorized**: no valid session (`getSession()` returns `null`). ```json { "error": { "message": "Unauthorized", "code": "AUTH_UNAUTHENTICATED" } } ``` - **403 Forbidden**: session exists but the user is not allowed to access the requested branch. ```json { "error": { "message": "Forbidden", "code": "AUTH_FORBIDDEN_BRANCH" } } ``` ### 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 ```json { "userId": "", "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` (invalid JSON/body) ```json { "error": { "message": "Invalid request body", "code": "VALIDATION_INVALID_JSON" } } ``` - `400` (missing username/password) ```json { "error": { "message": "Missing username or password", "code": "VALIDATION_MISSING_FIELD", "details": { "fields": ["username", "password"] } } } ``` - `401` (invalid credentials) ```json { "error": { "message": "Invalid credentials", "code": "AUTH_INVALID_CREDENTIALS" } } ``` - `500` ```json { "error": { "message": "Internal server error", "code": "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`.