diff --git a/workspace/_assets_/nav-data.js b/workspace/_assets_/nav-data.js index 1aa5302..0695fa8 100644 --- a/workspace/_assets_/nav-data.js +++ b/workspace/_assets_/nav-data.js @@ -38,6 +38,7 @@ var NAV_DATA = { title: 'History', path: 'history/index.html', children: [ + { title: 'Sunday, 13 July 2026', path: 'history/2026/07-July/13-Sunday/index.html' }, { title: 'Sunday, 12 July 2026', path: 'history/2026/07-July/12-Sunday/index.html' }, { title: 'Saturday, 11 July 2026', path: 'history/2026/07-July/11-Saturday/index.html' }, { title: 'Friday, 10 July 2026', path: 'history/2026/07-July/10-Friday/index.html' }, diff --git a/workspace/history/2026/07-July/13-Sunday/index.html b/workspace/history/2026/07-July/13-Sunday/index.html new file mode 100644 index 0000000..0495396 --- /dev/null +++ b/workspace/history/2026/07-July/13-Sunday/index.html @@ -0,0 +1,177 @@ + + + + + + Sunday, 13 July 2026 — Roject + + + + +
+ +
+

Sunday, 13 July 2026

+

rokojori-auth — built and deployed

+

+ Full centralized auth service created from scratch, deployed to + account.rokojori.com, and documented. +

+
+ +
+

What we built

+ +
+

rokojori-auth — new standalone service

+

+ A complete auth service at c:\rokojori\projects\web-projects\rokojori-auth, + same stack as Roject (Node.js, Express, ts-node, JSON file storage). Built entirely + from scratch this session. Deployed to account.rokojori.com via nginx + + systemd + Let's Encrypt on Server A, port 3001. +

+
+ account.rokojori.com + nginx + systemd + port 3001 +
+
+ +
+

Auth endpoints

+

+ Register, login, logout, refresh (body), refresh-session (cookie + redirect), + forgot-password, reset-password, GET /me, PATCH /me/settings, POST /me/password, + DELETE /me. Access token is a 1-hour HS256 JWT containing userId, email, roles, + products, settings. Refresh token is a 30-day UUID stored server-side. + Both are set as HttpOnly cookies on .rokojori.com + and also returned in the response body for non-browser clients. +

+
+ jsonwebtoken + bcryptjs + cookie-parser + HttpOnly cookie + .rokojori.com domain +
+
+ +
+

Roles: user, admin, superadmin

+

+ Three built-in roles. superadmin is bootstrapped via + INITIAL_SUPERADMIN_EMAIL in .env — fires once on + first registration if no superadmin exists. Superadmin can grant/revoke admin + on other users; cannot change their own roles. Admin and superadmin get an + enhanced profile page with a full user list. Role management controls are + superadmin-only. +

+
+ +
+

Rate limiting

+

+ In-memory per-IP rate limiters on all sensitive endpoints. Login: 10 attempts / + 15 min, 3 s delay after attempt 5. Register: 5 / hour. Forgot-password: 20 / 20 min + with escalating delay (5 s → 15 s → 30 s). trust proxy enabled so + real client IPs are seen behind nginx. +

+
+ +
+

HTML pages

+

+ Five self-contained pages: login, register, profile, forgot-password, reset-password. + Plain HTML with inline CSS and JS. Login and register accept a ?redirect= + query param. Reset-password fetches the email for the token via + GET /api/auth/reset-token-email and populates a hidden email field + so browsers offer to update the saved password. Profile page includes + change-password (with current password verification) and a two-step delete account + confirmation. Welcome email sent on registration (non-blocking). +

+
+ +
+

Admin routes

+

+ GET /api/admin/users (admin + superadmin) lists all users without + password hashes. PATCH /api/admin/users/:id/roles (superadmin only) + sets roles on another user. Guards: cannot change own roles; user + base role is always preserved. +

+
+ +
+

Workspace documentation

+

+ Created workspace/ in the rokojori-auth repo with the same asset + system as the Roject workspace (styles, nav, breadcrumb). A single + workspace/index.html covers features, technical implementation, + data model, JWT payload, deployment, planned work, and a reference to the + Roject workspace for guides and actions. +

+
+
+ +
+

Key decisions

+ +
+ Refresh token also set as HttpOnly cookie +

+ Originally the refresh token was only returned in the response body. Added a + refresh token cookie so browser clients can silently refresh via + GET /api/auth/refresh-session?redirect=... without re-login. + Non-browser clients continue to use the body token and + POST /api/auth/refresh. +

+
+ +
+ Superadmin cannot change their own roles +

+ The PATCH /api/admin/users/:id/roles endpoint blocks changes to the calling + user's own record to prevent accidental self-demotion or lockout. +

+
+ +
+ Welcome email is non-blocking +

+ SMTP failures on the welcome email are caught and silently ignored so that a + misconfigured mail server cannot break user registration. +

+
+ +
+ Forgot-password always returns OK +

+ The response is always { ok: true } regardless of whether the email + exists, preventing account enumeration via timing or response differences. +

+
+
+ +
+

What's next

+ +
+

+ Integrate Roject with rokojori-auth: remove the local user system from Roject, + add JWT verification middleware, redirect login/logout to + account.rokojori.com, and update all data references from local + user records to userId from the JWT payload. +

+
+
+ + + +
+ + + + + diff --git a/workspace/history/index.html b/workspace/history/index.html index 30cdef6..a861ac1 100644 --- a/workspace/history/index.html +++ b/workspace/history/index.html @@ -19,6 +19,11 @@

2026 — July

+
+

Sunday, 13 July 2026

+

rokojori-auth built and deployed — standalone auth service at account.rokojori.com with JWT tokens, refresh cookies, roles, rate limiting, admin panel, and workspace documentation.

+
+

Sunday, 12 July 2026

Full directory restructure and first production deployment — source/, build/, source/pages/; Roject live at roject.rokojori.com via nginx + systemd. EmailService SMTP layer added.

diff --git a/workspace/outline/index.html b/workspace/outline/index.html index 0030651..ba04077 100644 --- a/workspace/outline/index.html +++ b/workspace/outline/index.html @@ -231,17 +231,17 @@
-

In progress — Centralized auth: rokojori-auth

+

Done — Centralized auth: rokojori-auth

- The user system currently embedded in Roject is being extracted into a - standalone auth service, rokojori-auth, deployed at - account.rokojori.com. It will handle registration, login, - JWT issuance, password reset, and user data (roles, products, settings) - for all rokojori projects. Roject will become a JWT-validating client - with no user storage of its own. + The standalone auth service rokojori-auth is built and live at + account.rokojori.com. It handles registration, login, JWT issuance, + refresh token rotation, password reset, roles (user / admin / superadmin), + products, global settings, rate limiting, and account deletion. + Roject has not yet been integrated — that is the next step.

- See auth-restructure for the full plan. + See auth-restructure for the full plan and + the rokojori-auth workspace for implementation details.

rokojori-auth @@ -251,6 +251,35 @@
+
+

Next — Roject integration with rokojori-auth

+

+ Roject needs to be updated to become a JWT-validating client. The work involves + removing the existing session-based user system and replacing it with JWT + verification middleware that reads the shared .rokojori.com cookie. + Login and register links will point to account.rokojori.com. + Expired tokens are refreshed via + account.rokojori.com/api/auth/refresh-session?redirect=.... + All data models that currently reference a local user record will switch to + referencing userId from the JWT payload. +

+ +
+ JWT middleware + remove express-session + remove bcryptjs + account.rokojori.com login redirect +
+
+

Smaller open improvements