Sunday, 13 July 2026
Full centralized auth service created from scratch, deployed to
account.rokojori.com, and documented.
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.
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.
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.
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.
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).
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.
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.
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.
The PATCH /api/admin/users/:id/roles endpoint blocks changes to the calling user's own record to prevent accidental self-demotion or lockout.
SMTP failures on the welcome email are caught and silently ignored so that a misconfigured mail server cannot break user registration.
The response is always { ok: true } regardless of whether the email
exists, preventing account enumeration via timing or response differences.
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.