|
|
@@ -1,9 +1,3 @@
|
|
|
-Perfekt, dann machen wir jetzt einmal eine **saubere, komplette `docs/auth.md`** mit allem, was wir bisher besprochen haben – inklusive des geplanten Epics **“Password management & recovery”**.
|
|
|
-
|
|
|
-Alles in Englisch, strukturiert, so dass du es 1:1 als Datei ablegen kannst.
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
# Authentication & Authorization
|
|
|
|
|
|
This document describes the authentication and authorization model for the internal delivery note browser.
|
|
|
@@ -13,7 +7,7 @@ The system uses:
|
|
|
- MongoDB to store users.
|
|
|
- Cookie-based sessions with a signed JWT payload.
|
|
|
- Role-aware access control (`branch`, `admin`, `dev`).
|
|
|
-- Future extensions for password management and recovery.
|
|
|
+- Extensible password management and recovery flows.
|
|
|
|
|
|
> NOTE: This document is a living document. As we extend the auth system (sessions, routes, policies, password flows), we will update this file.
|
|
|
|
|
|
@@ -33,6 +27,7 @@ The main goals of the authentication system are:
|
|
|
This document covers:
|
|
|
|
|
|
- User model and roles.
|
|
|
+- Environment variables related to auth.
|
|
|
- Session payload and cookie configuration.
|
|
|
- Login and logout endpoints.
|
|
|
- Planned endpoints for password management and recovery.
|
|
|
@@ -40,11 +35,31 @@ This document covers:
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 2. User Model
|
|
|
+## 2. Environment Variables
|
|
|
+
|
|
|
+The authentication system depends on the following environment variables:
|
|
|
+
|
|
|
+- `SESSION_SECRET` (required)
|
|
|
+
|
|
|
+ - Strong, random string used to sign and verify JWT session tokens.
|
|
|
+ - Must be kept secret and should differ between environments (dev, staging, prod).
|
|
|
+
|
|
|
+Example for `.env.local.example`:
|
|
|
+
|
|
|
+```env
|
|
|
+# Session / JWT
|
|
|
+SESSION_SECRET=change-me-to-a-long-random-string
|
|
|
+```
|
|
|
+
|
|
|
+If `SESSION_SECRET` is not set, session utilities will throw an error.
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3. User Model
|
|
|
|
|
|
Users are stored in MongoDB using the `User` collection.
|
|
|
|
|
|
-### 2.1 Fields
|
|
|
+### 3.1 Fields
|
|
|
|
|
|
- **username** (`String`, required, unique, lowercased)
|
|
|
|
|
|
@@ -56,7 +71,8 @@ Users are stored in MongoDB using the `User` collection.
|
|
|
- **email** (`String`, required, unique, lowercased)
|
|
|
|
|
|
- Contact address used for password recovery and notifications.
|
|
|
- - Typically the branch email address for branch accounts, or a personal email address for individual users.
|
|
|
+ - For branch accounts, this is typically the branch email address.
|
|
|
+ - For individual accounts, this can be the personal work email.
|
|
|
- Stored in lowercase.
|
|
|
- Unique per user.
|
|
|
|
|
|
@@ -100,20 +116,22 @@ Users are stored in MongoDB using the `User` collection.
|
|
|
- Timestamp when the user record was created.
|
|
|
|
|
|
- **updatedAt** (`Date`, auto-generated)
|
|
|
+
|
|
|
- Timestamp when the user record was last updated.
|
|
|
|
|
|
-### 2.2 Validation Rules & Invariants
|
|
|
+### 3.2 Validation Rules & Invariants
|
|
|
|
|
|
- `username` must be unique and is stored in lowercase.
|
|
|
- `email` must be unique and is stored in lowercase.
|
|
|
- `passwordHash` must be present for all users.
|
|
|
- When `role = "branch"`, `branchId` must be a non-empty string.
|
|
|
- For `role = "admin"` and `role = "dev"`, `branchId` is optional and usually `null`.
|
|
|
-- `passwordResetToken` and `passwordResetExpiresAt` must be consistent:
|
|
|
+- `passwordResetToken` and `passwordResetExpiresAt` should be consistent:
|
|
|
+
|
|
|
- If one is set, the other should also be set.
|
|
|
- Once a reset is completed or expired, both should be cleared.
|
|
|
|
|
|
-### 2.3 Serialization Rules
|
|
|
+### 3.3 Serialization Rules
|
|
|
|
|
|
When converting `User` documents to JSON or plain objects (e.g. in API responses), the following fields must be hidden:
|
|
|
|
|
|
@@ -122,55 +140,63 @@ When converting `User` documents to JSON or plain objects (e.g. in API responses
|
|
|
|
|
|
This ensures that sensitive information is not exposed via API responses or logs.
|
|
|
|
|
|
+### 3.4 Role Assignment & User Provisioning
|
|
|
+
|
|
|
+- Users are **created by an admin** (no public self-registration).
|
|
|
+- When a user is created:
|
|
|
+
|
|
|
+ - `role` is set by the admin.
|
|
|
+ - `branchId` is set by the admin and cannot be chosen or changed by the user.
|
|
|
+
|
|
|
+- For branch accounts, we typically create one or more users per branch with:
|
|
|
+
|
|
|
+ - `role = "branch"`
|
|
|
+ - `branchId` set to the respective branch identifier (e.g. `"NL01"`).
|
|
|
+
|
|
|
+- The user is provided with an initial password and is encouraged (or forced via `mustChangePassword`) to change it after the first login.
|
|
|
+
|
|
|
---
|
|
|
|
|
|
-## 3. Roles
|
|
|
+## 4. Roles
|
|
|
|
|
|
-### 3.1 `branch`
|
|
|
+### 4.1 `branch`
|
|
|
|
|
|
- Represents a user who belongs to a specific branch/location.
|
|
|
- Must have a valid `branchId` (e.g. `"NL01"`).
|
|
|
- Intended access pattern (high-level):
|
|
|
+
|
|
|
- Can only access delivery notes for their own branch.
|
|
|
- Cannot access other branches.
|
|
|
- No global configuration or system-wide administration.
|
|
|
|
|
|
-### 3.2 `admin`
|
|
|
+### 4.2 `admin`
|
|
|
|
|
|
- System administrator.
|
|
|
- Typically not bound to any single branch (`branchId = null`).
|
|
|
- Intended access pattern (high-level):
|
|
|
+
|
|
|
- Can access delivery notes across all branches.
|
|
|
- Can perform user administration (create/update users).
|
|
|
- Can perform configuration-level changes.
|
|
|
|
|
|
-### 3.3 `dev`
|
|
|
+### 4.3 `dev`
|
|
|
|
|
|
- Development/engineering account.
|
|
|
- Used for debugging, maintenance, and operational tooling.
|
|
|
- Typically not bound to any single branch (`branchId = null`).
|
|
|
- Intended access pattern (high-level):
|
|
|
+
|
|
|
- Full or near-full access to the system.
|
|
|
- Can be used in development/staging environments.
|
|
|
- Production use should be limited and auditable.
|
|
|
|
|
|
-### 3.4 Role Assignment & User Provisioning
|
|
|
-
|
|
|
-- Users are **created by an admin** (no public self-registration).
|
|
|
-- When a user is created:
|
|
|
- - `role` is set by the admin.
|
|
|
- - `branchId` is set by the admin and cannot be chosen by the user.
|
|
|
-- For branch accounts, we typically create one or more users per branch with:
|
|
|
- - `role = "branch"`
|
|
|
- - `branchId` set to the respective branch identifier.
|
|
|
-
|
|
|
---
|
|
|
|
|
|
-## 4. Sessions & Cookies
|
|
|
+## 5. Sessions & Cookies
|
|
|
|
|
|
Sessions are implemented as signed JWTs stored in HTTP-only cookies.
|
|
|
|
|
|
-### 4.1 Session Payload Format
|
|
|
+### 5.1 Session Payload Format
|
|
|
|
|
|
A session payload has the following structure:
|
|
|
|
|
|
@@ -192,51 +218,60 @@ A session payload has the following structure:
|
|
|
|
|
|
The `iat` and `exp` fields are managed by the JWT library.
|
|
|
|
|
|
-### 4.2 JWT Signing
|
|
|
-
|
|
|
-- The JWT is signed using a symmetric secret (`SESSION_SECRET`).
|
|
|
-
|
|
|
-- Recommended algorithm: `HS256` (HMAC using SHA-256).
|
|
|
-
|
|
|
-- The secret is defined via environment variable:
|
|
|
-
|
|
|
- - `SESSION_SECRET` (required, strong random string)
|
|
|
+### 5.2 JWT Signing
|
|
|
|
|
|
-- Token lifetime (example):
|
|
|
+- JWTs are signed using a symmetric secret (`SESSION_SECRET`).
|
|
|
+- Algorithm: `HS256` (HMAC using SHA-256).
|
|
|
+- Secret is defined via environment variable `SESSION_SECRET`.
|
|
|
+- Token lifetime:
|
|
|
|
|
|
- - Access token / session lifetime: e.g. 8 hours (configurable).
|
|
|
+ - `SESSION_MAX_AGE_SECONDS = 60 * 60 * 8` (8 hours).
|
|
|
+ - Configured in `lib/auth/session.js`.
|
|
|
|
|
|
-### 4.3 Cookie Settings
|
|
|
+### 5.3 Cookie Settings
|
|
|
|
|
|
-The session token is stored in an HTTP-only cookie, for example:
|
|
|
+The session token is stored in an HTTP-only cookie with the following properties:
|
|
|
|
|
|
-- **Cookie name**: `auth_session` (TBD, but must be consistent across backend/frontend)
|
|
|
+- **Cookie name**: `auth_session`
|
|
|
- **Attributes**:
|
|
|
|
|
|
- `httpOnly: true`
|
|
|
- `secure: process.env.NODE_ENV === "production"`
|
|
|
- - `sameSite: "lax"` (or stricter, e.g. `"strict"` if acceptable)
|
|
|
+ - `sameSite: "lax"`
|
|
|
- `path: "/"` (cookie is sent for all paths)
|
|
|
- - `maxAge`: matches or slightly exceeds the JWT `exp` lifetime.
|
|
|
+ - `maxAge: 8 hours` (matching `SESSION_MAX_AGE_SECONDS`)
|
|
|
|
|
|
-Cookies are written and cleared using Next.js `NextResponse` helpers in API routes.
|
|
|
+Cookies are written and cleared using Next.js `cookies()` from `next/headers` inside `lib/auth/session.js`:
|
|
|
|
|
|
----
|
|
|
+- `createSession({ userId, role, branchId })`:
|
|
|
+
|
|
|
+ - Creates and signs a JWT.
|
|
|
+ - Sets the `auth_session` cookie.
|
|
|
+
|
|
|
+- `getSession()`:
|
|
|
|
|
|
-## 5. Auth Endpoints (Core)
|
|
|
+ - Reads the `auth_session` cookie.
|
|
|
+ - Verifies the JWT and returns `{ userId, role, branchId }` or `null`.
|
|
|
+ - If the token is invalid or expired, clears the cookie and returns `null`.
|
|
|
|
|
|
-The core auth endpoints handle login and logout using the session cookie.
|
|
|
+- `destroySession()`:
|
|
|
+
|
|
|
+ - Clears the `auth_session` cookie by setting an empty value with `maxAge: 0`.
|
|
|
+
|
|
|
+---
|
|
|
|
|
|
-### 5.1 `POST /api/auth/login`
|
|
|
+## 6. Core Auth Endpoints
|
|
|
|
|
|
-**Purpose:**
|
|
|
+### 6.1 `POST /api/auth/login`
|
|
|
+
|
|
|
+**Purpose**
|
|
|
Authenticate a user using `username` and `password`, create a session, and set the session cookie.
|
|
|
|
|
|
-**Method & URL:**
|
|
|
+**Method & URL**
|
|
|
|
|
|
- `POST /api/auth/login`
|
|
|
|
|
|
-**Request Body (JSON):**
|
|
|
+**Request Body (JSON)**
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
@@ -248,101 +283,148 @@ Authenticate a user using `username` and `password`, create a session, and set t
|
|
|
- `username` (string): Login name (case-insensitive).
|
|
|
- `password` (string): Plaintext password entered by the user.
|
|
|
|
|
|
-**Behavior:**
|
|
|
+**Behavior**
|
|
|
+
|
|
|
+1. Normalize `username`:
|
|
|
+
|
|
|
+ - Trim whitespace and convert to lowercase.
|
|
|
+
|
|
|
+2. Parse and validate request body:
|
|
|
+
|
|
|
+ - If body is missing or invalid JSON → `400 { "error": "Invalid request body" }`.
|
|
|
+ - If `username` or `password` is missing or empty → `400 { "error": "Missing username or password" }`.
|
|
|
+
|
|
|
+3. Connect to MongoDB.
|
|
|
+4. Look up the user in MongoDB by normalized `username`.
|
|
|
+
|
|
|
+ - If no user is found → `401 { "error": "Invalid credentials" }`.
|
|
|
+
|
|
|
+5. Verify the password using bcrypt:
|
|
|
+
|
|
|
+ - Compare provided `password` with `user.passwordHash`.
|
|
|
+ - If password does not match → `401 { "error": "Invalid credentials" }`.
|
|
|
|
|
|
-1. Normalize `username` (trim + lowercase).
|
|
|
-2. Look up the user in MongoDB by `username`.
|
|
|
-3. If user not found → return `401` with `{ "error": "Invalid credentials" }`.
|
|
|
-4. Verify the password using bcrypt (compare with `passwordHash`).
|
|
|
-5. If password does not match → return `401` with `{ "error": "Invalid credentials" }`.
|
|
|
6. On success:
|
|
|
|
|
|
- Create a session payload `{ userId, role, branchId }`.
|
|
|
- - Sign a JWT using `SESSION_SECRET`.
|
|
|
- - Set the JWT in the `auth_session` HTTP-only cookie.
|
|
|
- - Return `200` with `{ "ok": true }`.
|
|
|
+ - Call `createSession({ userId, role, branchId })`:
|
|
|
|
|
|
-**Successful Response (200):**
|
|
|
+ - Signs a JWT with the session payload.
|
|
|
+ - Sets the `auth_session` HTTP-only cookie.
|
|
|
|
|
|
-```json
|
|
|
-{
|
|
|
- "ok": true
|
|
|
-}
|
|
|
-```
|
|
|
+ - Return `200 { "ok": true }`.
|
|
|
+
|
|
|
+**Possible Responses**
|
|
|
+
|
|
|
+- `200 OK`:
|
|
|
|
|
|
-(Session cookie is set in the response headers.)
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "ok": true
|
|
|
+ }
|
|
|
+ ```
|
|
|
|
|
|
-**Error Responses:**
|
|
|
+ (Session cookie is set in the response headers.)
|
|
|
|
|
|
- `400 Bad Request`:
|
|
|
|
|
|
- - Missing `username` or `password`.
|
|
|
- - Invalid body format.
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "error": "Invalid request body"
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+ or
|
|
|
+
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "error": "Missing username or password"
|
|
|
+ }
|
|
|
+ ```
|
|
|
|
|
|
- `401 Unauthorized`:
|
|
|
|
|
|
- - User not found.
|
|
|
- - Password does not match.
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "error": "Invalid credentials"
|
|
|
+ }
|
|
|
+ ```
|
|
|
|
|
|
- `500 Internal Server Error`:
|
|
|
|
|
|
- - Unexpected server-side error.
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "error": "Internal server error"
|
|
|
+ }
|
|
|
+ ```
|
|
|
|
|
|
-### 5.2 `GET /api/auth/logout`
|
|
|
+### 6.2 `GET /api/auth/logout`
|
|
|
|
|
|
-**Purpose:**
|
|
|
+**Purpose**
|
|
|
Destroy the current session by clearing the session cookie.
|
|
|
|
|
|
-**Method & URL:**
|
|
|
+**Method & URL**
|
|
|
|
|
|
- `GET /api/auth/logout`
|
|
|
|
|
|
-**Request:**
|
|
|
+**Request**
|
|
|
|
|
|
- No request body.
|
|
|
- Uses the current session cookie (if present).
|
|
|
|
|
|
-**Behavior:**
|
|
|
+**Behavior**
|
|
|
+
|
|
|
+1. Call `destroySession()`:
|
|
|
|
|
|
-1. Clear the `auth_session` cookie (e.g. by setting an expired cookie).
|
|
|
-2. Return `200` with `{ "ok": true }`.
|
|
|
+ - Clears the `auth_session` cookie by setting an empty value with `maxAge: 0`.
|
|
|
+
|
|
|
+2. Return `200 { "ok": true }`.
|
|
|
|
|
|
Logout is **idempotent**:
|
|
|
|
|
|
- If the cookie does not exist, the endpoint still returns `{ "ok": true }`.
|
|
|
|
|
|
-**Response (200):**
|
|
|
+**Responses**
|
|
|
|
|
|
-```json
|
|
|
-{
|
|
|
- "ok": true
|
|
|
-}
|
|
|
-```
|
|
|
+- `200 OK`:
|
|
|
+
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "ok": true
|
|
|
+ }
|
|
|
+ ```
|
|
|
+
|
|
|
+- `500 Internal Server Error` (if `destroySession` throws):
|
|
|
+
|
|
|
+ ```json
|
|
|
+ {
|
|
|
+ "error": "Internal server error"
|
|
|
+ }
|
|
|
+ ```
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 6. Password Management & Recovery (Planned)
|
|
|
+## 7. Password Management & Recovery (Planned)
|
|
|
|
|
|
-This section describes the **planned** password management and recovery flows.
|
|
|
-The database model is already prepared for these scenarios, even if the endpoints are not yet implemented.
|
|
|
+The database model is already prepared for password management and password recovery flows, but the respective endpoints may be implemented in a separate epic.
|
|
|
|
|
|
-### 6.1 Change Password
|
|
|
+### 7.1 Change Password
|
|
|
|
|
|
-**Endpoint:** `POST /api/auth/change-password`
|
|
|
-**Status:** Planned.
|
|
|
+**Endpoint**
|
|
|
+`POST /api/auth/change-password` (planned)
|
|
|
|
|
|
-**Purpose:**
|
|
|
+**Purpose**
|
|
|
Allow logged-in users to change their password by providing the current password and a new password.
|
|
|
|
|
|
-**Method & URL:**
|
|
|
+**Method & URL**
|
|
|
|
|
|
- `POST /api/auth/change-password`
|
|
|
|
|
|
-**Authentication:**
|
|
|
+**Authentication**
|
|
|
|
|
|
- Requires a valid session (user must be logged in).
|
|
|
|
|
|
-**Request Body (JSON):**
|
|
|
+**Request Body (JSON)**
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
@@ -351,39 +433,31 @@ Allow logged-in users to change their password by providing the current password
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-**Behavior (planned):**
|
|
|
+**Planned Behavior**
|
|
|
|
|
|
-1. Extract `userId` from the current session.
|
|
|
+1. Extract `userId` from the current session (`getSession()`).
|
|
|
2. Load user from MongoDB.
|
|
|
3. Verify `currentPassword` against `passwordHash` using bcrypt.
|
|
|
-4. If verification fails → return `400` or `401` with a generic error (e.g. `{ "error": "Invalid password" }`).
|
|
|
+4. If verification fails → return a generic error (e.g. `400` or `401` with `{ "error": "Invalid password" }`).
|
|
|
5. Hash `newPassword` with bcrypt.
|
|
|
6. Update `passwordHash` in the database.
|
|
|
7. Optionally set `mustChangePassword = false`.
|
|
|
8. Optionally update a `passwordChangedAt` field if introduced later.
|
|
|
9. Return `{ "ok": true }`.
|
|
|
|
|
|
-**Response (200):**
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "ok": true
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 6.2 Request Password Reset
|
|
|
+### 7.2 Request Password Reset
|
|
|
|
|
|
-**Endpoint:** `POST /api/auth/request-password-reset`
|
|
|
-**Status:** Planned.
|
|
|
+**Endpoint**
|
|
|
+`POST /api/auth/request-password-reset` (planned)
|
|
|
|
|
|
-**Purpose:**
|
|
|
+**Purpose**
|
|
|
Start the "forgot password" flow by sending a reset link to the user's email address.
|
|
|
|
|
|
-**Method & URL:**
|
|
|
+**Method & URL**
|
|
|
|
|
|
- `POST /api/auth/request-password-reset`
|
|
|
|
|
|
-**Request Body (JSON):**
|
|
|
+**Request Body (JSON)**
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
@@ -393,11 +467,11 @@ Start the "forgot password" flow by sending a reset link to the user's email add
|
|
|
|
|
|
- The frontend may allow either username or email. The backend resolves it accordingly.
|
|
|
|
|
|
-**Behavior (planned):**
|
|
|
+**Planned Behavior**
|
|
|
|
|
|
1. Normalize the identifier (trim + lowercase).
|
|
|
|
|
|
-2. Try to find a user by `email` (and optionally by `username` if needed).
|
|
|
+2. Try to find a user by `email` (and optionally by `username`).
|
|
|
|
|
|
3. If no user is found:
|
|
|
|
|
|
@@ -422,27 +496,19 @@ Start the "forgot password" flow by sending a reset link to the user's email add
|
|
|
|
|
|
5. Always return `{ "ok": true }` to the client, regardless of whether a user was found.
|
|
|
|
|
|
-**Response (200):**
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "ok": true
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 6.3 Reset Password
|
|
|
+### 7.3 Reset Password
|
|
|
|
|
|
-**Endpoint:** `POST /api/auth/reset-password`
|
|
|
-**Status:** Planned.
|
|
|
+**Endpoint**
|
|
|
+`POST /api/auth/reset-password` (planned)
|
|
|
|
|
|
-**Purpose:**
|
|
|
+**Purpose**
|
|
|
Complete the password reset process using a valid reset token.
|
|
|
|
|
|
-**Method & URL:**
|
|
|
+**Method & URL**
|
|
|
|
|
|
- `POST /api/auth/reset-password`
|
|
|
|
|
|
-**Request Body (JSON):**
|
|
|
+**Request Body (JSON)**
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
@@ -451,12 +517,16 @@ Complete the password reset process using a valid reset token.
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-**Behavior (planned):**
|
|
|
+**Planned Behavior**
|
|
|
|
|
|
1. Find user by `passwordResetToken`.
|
|
|
2. If no user is found → return a generic error (e.g. `{ "error": "Invalid or expired token" }`).
|
|
|
3. Check that `passwordResetExpiresAt` is in the future.
|
|
|
-4. If the token has expired → return a generic error and clear token/expiry fields.
|
|
|
+4. If the token has expired:
|
|
|
+
|
|
|
+ - Return a generic error.
|
|
|
+ - Clear `passwordResetToken` and `passwordResetExpiresAt`.
|
|
|
+
|
|
|
5. If the token is valid:
|
|
|
|
|
|
- Hash `newPassword` with bcrypt.
|
|
|
@@ -467,15 +537,7 @@ Complete the password reset process using a valid reset token.
|
|
|
6. Optionally invalidate other active sessions if a "global logout on password change" is implemented.
|
|
|
7. Return `{ "ok": true }`.
|
|
|
|
|
|
-**Response (200):**
|
|
|
-
|
|
|
-```json
|
|
|
-{
|
|
|
- "ok": true
|
|
|
-}
|
|
|
-```
|
|
|
-
|
|
|
-### 6.4 Email Sending
|
|
|
+### 7.4 Email Sending
|
|
|
|
|
|
Password reset emails will be sent using a mailer library (e.g. `nodemailer`), configured for the environment.
|
|
|
|
|
|
@@ -492,7 +554,7 @@ Key points:
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 7. Security Considerations
|
|
|
+## 8. Security Considerations
|
|
|
|
|
|
1. **Never trust client-provided `branchId`.**
|
|
|
|
|
|
@@ -527,25 +589,26 @@ Key points:
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 8. Open Points & Future Work
|
|
|
+## 9. Future Work & Integration
|
|
|
|
|
|
-- Implement the session utility (`lib/auth/session.js`) with:
|
|
|
+- Protect existing filesystem APIs (`/api/branches/*`, `/api/files`, etc.) by:
|
|
|
|
|
|
- - `createSession({ userId, role, branchId })`
|
|
|
- - `getSession()`
|
|
|
- - `destroySession()`
|
|
|
+ - Calling `getSession()` at the start of each route.
|
|
|
+ - Returning `401` if no valid session exists.
|
|
|
+ - Resolving the effective `branchId` from the session and enforcing that branch users only see their own branch.
|
|
|
|
|
|
-- Implement the login and logout endpoints as described above.
|
|
|
- Implement password management endpoints:
|
|
|
|
|
|
- `POST /api/auth/change-password`
|
|
|
- `POST /api/auth/request-password-reset`
|
|
|
- `POST /api/auth/reset-password`
|
|
|
|
|
|
-- Implement email sending for password reset using `nodemailer` or similar.
|
|
|
-- Implement a UI for:
|
|
|
+- Integrate an email provider using `nodemailer` or similar for password reset.
|
|
|
+- Build frontend UI for:
|
|
|
|
|
|
- Login
|
|
|
- Logout
|
|
|
- Change password
|
|
|
- “Forgot password” / reset password flows.
|
|
|
+
|
|
|
+- Optionally extend auditing and logging for security-relevant events.
|