|
|
@@ -29,6 +29,7 @@ This document covers:
|
|
|
- Session payload and cookie configuration.
|
|
|
- Auth endpoints (login/logout/me).
|
|
|
- Password change (authenticated users).
|
|
|
+- Must-change-password enforcement semantics (`mustChangePassword`).
|
|
|
|
|
|
Non-goals (for this document):
|
|
|
|
|
|
@@ -244,6 +245,7 @@ Sessions are implemented as signed JWTs stored in HTTP-only cookies.
|
|
|
"role": "branch | admin | superadmin | dev",
|
|
|
"branchId": "NL01 | null",
|
|
|
"email": "name@company.tld | null",
|
|
|
+ "mustChangePassword": "boolean",
|
|
|
"iat": 1700000000,
|
|
|
"exp": 1700003600
|
|
|
}
|
|
|
@@ -252,7 +254,9 @@ Sessions are implemented as signed JWTs stored in HTTP-only cookies.
|
|
|
Notes:
|
|
|
|
|
|
- `email` is optional and may be `null`.
|
|
|
+- `mustChangePassword` is always normalized to a boolean (`true` only when explicitly set to `true`; otherwise `false`).
|
|
|
- The session email is used for displaying read-only account information in the UI (Profile).
|
|
|
+- `mustChangePassword` is consumed by frontend auth gating (RHL-044).
|
|
|
|
|
|
### 5.2 JWT signing
|
|
|
|
|
|
@@ -274,7 +278,7 @@ Attributes:
|
|
|
|
|
|
Implementation lives in `lib/auth/session.js`:
|
|
|
|
|
|
-- `createSession({ userId, role, branchId, email })`
|
|
|
+- `createSession({ userId, role, branchId, email, mustChangePassword })`
|
|
|
- `getSession()`
|
|
|
- `destroySession()`
|
|
|
|
|
|
@@ -362,7 +366,8 @@ Response (authenticated):
|
|
|
"userId": "...",
|
|
|
"role": "branch|admin|superadmin|dev",
|
|
|
"branchId": "NL01",
|
|
|
- "email": "nl01@example.com"
|
|
|
+ "email": "nl01@example.com",
|
|
|
+ "mustChangePassword": true
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
@@ -370,6 +375,7 @@ Response (authenticated):
|
|
|
Notes:
|
|
|
|
|
|
- `email` is optional and may be `null`.
|
|
|
+- `mustChangePassword` is always returned as a boolean.
|
|
|
- The endpoint intentionally returns only minimal identity information needed by the UI.
|
|
|
|
|
|
---
|
|
|
@@ -436,7 +442,21 @@ Behavior:
|
|
|
- `passwordResetToken = null`
|
|
|
- `passwordResetExpiresAt = null`
|
|
|
|
|
|
-### 7.4 Password reset (planned, separate ticket)
|
|
|
+7. Refresh the session cookie with `mustChangePassword = false` so frontend revalidation immediately sees the cleared gate state.
|
|
|
+
|
|
|
+### 7.4 Must-change-password enforcement (RHL-044)
|
|
|
+
|
|
|
+Frontend behavior for authenticated users with `mustChangePassword = true`:
|
|
|
+
|
|
|
+- The protected UI is gated centrally via `AuthGate`.
|
|
|
+- Users are redirected to `/profile` until the password is changed.
|
|
|
+- `/profile` displays a clear required-action alert in German.
|
|
|
+- After a successful password change:
|
|
|
+ - backend clears `mustChangePassword`
|
|
|
+ - backend refreshes the session cookie
|
|
|
+ - frontend revalidates auth state and automatically lifts the gate
|
|
|
+
|
|
|
+### 7.5 Password reset (planned, separate ticket)
|
|
|
|
|
|
The user model includes fields that allow implementing password reset flows:
|
|
|
|