history+outline: Roject JWT integration with rokojori-auth

This commit is contained in:
Rokojori 2026-07-13 15:37:19 +02:00
parent e89a372152
commit ea58d0d102
3 changed files with 89 additions and 32 deletions

View File

@ -12,10 +12,11 @@
<header>
<p class="date">Sunday, 13 July 2026</p>
<h1>rokojori-auth — built and deployed</h1>
<h1>rokojori-auth built + Roject integration</h1>
<p class="subtitle">
Full centralized auth service created from scratch, deployed to
<code>account.rokojori.com</code>, and documented.
Full centralized auth service created and deployed to
<code>account.rokojori.com</code>; Roject's local user system replaced
with JWT verification against rokojori-auth.
</p>
</header>
@ -152,15 +153,75 @@
</div>
</section>
<section>
<h2>What we built — Roject integration</h2>
<div class="card">
<h3>Local auth system removed</h3>
<p>
Deleted <code>routes/auth.ts</code>, <code>sessionStore.ts</code>,
<code>email/</code>, <code>login.html</code>, <code>register.html</code>,
and the <code>login-form</code> and <code>register-form</code> components.
Removed <code>bcryptjs</code> and <code>express-session</code> from
<code>package.json</code>. Removed the <code>User</code> model and
<code>users</code> store from <code>db.ts</code>.
</p>
</div>
<div class="card">
<h3>JWT verification middleware</h3>
<p>
New <code>source/server/middleware/auth.ts</code> reads the
<code>accessToken</code> cookie (or <code>Authorization: Bearer</code> header),
verifies it with the shared <code>JWT_SECRET</code>, and attaches
<code>req.user</code>. Expired tokens on page requests are transparently
redirected to <code>account.rokojori.com/api/auth/refresh-session?redirect=...</code>.
API routes return <code>401</code> when unauthenticated.
Added <code>cookie-parser</code> and <code>jsonwebtoken</code>.
</p>
</div>
<div class="card">
<h3>app-nav updated</h3>
<p>
<code>app-nav.ts</code> now calls <code>GET /api/auth/me</code> on Roject
(which returns <code>req.user</code> from the JWT). On 401 it renders a
"Log in" link pointing to
<code>account.rokojori.com/login.html?redirect=https://roject.rokojori.com</code>.
When authenticated it shows the user's email and a logout link to
<code>account.rokojori.com/api/auth/logout?redirect=...</code>.
</p>
</div>
<div class="card">
<h3>GET /logout added to rokojori-auth</h3>
<p>
Added <code>GET /api/auth/logout?redirect=...</code> to rokojori-auth,
mirroring the <code>refresh-session</code> pattern. Clears both cookies,
invalidates the refresh token, and redirects to the given URL.
</p>
</div>
<div class="card">
<h3>systemd EnvironmentFile</h3>
<p>
Roject's systemd service had no environment variables configured, so
<code>JWT_SECRET</code> was silently empty and all JWT verifications failed.
Fixed by adding <code>EnvironmentFile=/opt/roject/.env</code> via
<code>systemctl edit roject</code> followed by a daemon-reload and restart.
</p>
</div>
</section>
<section>
<h2>What's next</h2>
<div class="card">
<p>
Integrate Roject with rokojori-auth: remove the local user system from Roject,
add JWT verification middleware, redirect login/logout to
<code>account.rokojori.com</code>, and update all data references from local
user records to <code>userId</code> from the JWT payload.
Landing screen for unauthenticated users — instead of crashing on dashboard
components, show a page that explains the app and offers a login link.
Also: graceful 401 handling in data-fetching components (groups, projects, etc.)
so they display a sensible message instead of throwing a JS error.
</p>
</div>
</section>

View File

@ -21,7 +21,7 @@
<div class="card">
<h3><a href="2026/07-July/13-Sunday/index.html">Sunday, 13 July 2026</a></h3>
<p>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.</p>
<p>rokojori-auth built and deployed; Roject local auth replaced with JWT middleware — cookie-based login via account.rokojori.com, systemd EnvironmentFile fix.</p>
</div>
<div class="card">

View File

@ -252,37 +252,31 @@
</div>
<div class="card">
<h3>Next — Roject integration with rokojori-auth</h3>
<h3>Done — Roject integration with rokojori-auth</h3>
<p>
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 <code>.rokojori.com</code> cookie.
Login and register links will point to <code>account.rokojori.com</code>.
Expired tokens are refreshed via
Roject is now a JWT-validating client. The local session-based user system has
been removed and replaced with a JWT verification middleware that reads the shared
<code>accessToken</code> cookie on <code>.rokojori.com</code>. Expired tokens are
transparently refreshed via
<code>account.rokojori.com/api/auth/refresh-session?redirect=...</code>.
All data models that currently reference a local user record will switch to
referencing <code>userId</code> from the JWT payload.
Login and logout links in <code>app-nav</code> point to
<code>account.rokojori.com</code>. All data references use <code>userId</code>
from the JWT payload. A <code>GET /api/auth/logout?redirect=...</code> endpoint
was also added to rokojori-auth to support browser-based logout links.
</p>
<ul style="line-height:1.9;margin-top:0.75rem;font-size:0.9rem">
<li>Remove <code>source/server/routes/auth.ts</code> and <code>middleware/auth.ts</code></li>
<li>Remove user storage from <code>source/server/db.ts</code></li>
<li>Remove <code>bcryptjs</code>, <code>express-session</code></li>
<li>Remove <code>source/pages/login.html</code>, <code>register.html</code></li>
<li>Remove <code>source/server/email/</code> (already lives in rokojori-auth)</li>
<li>Add JWT verification middleware</li>
<li>Point login/logout nav links at <code>account.rokojori.com</code></li>
</ul>
<div class="tags">
<span class="tag">JWT middleware</span>
<span class="tag">remove express-session</span>
<span class="tag">remove bcryptjs</span>
<span class="tag">account.rokojori.com login redirect</span>
<span class="tag">cookie-parser</span>
<span class="tag">jsonwebtoken</span>
<span class="tag">account.rokojori.com</span>
</div>
</div>
<div class="card">
<h3>Smaller open improvements</h3>
<ul style="line-height:1.9">
<li>Unauthenticated users should land on a landing screen that explains the app and shows a login link, rather than crashing on dashboard components.</li>
<li>Components that fetch data (groups, projects, etc.) do not handle <code>401</code> responses gracefully — they crash when the API returns an error object instead of an array.</li>
<li>The Right panel has no default content and relies on manual tab dragging to populate.</li>
<li>Portrait mode's secondary section switcher (when a panel has multiple side-by-side sections) is not yet wired up.</li>
<li>The member list UI shows raw UUIDs instead of usernames.</li>
@ -302,8 +296,10 @@
<p>
Node.js + Express, TypeScript compiled on the fly with <code>ts-node</code>.
No database — all data lives as JSON files in <code>data/</code>
(auto-created on first run). Auth uses <code>express-session</code> +
<code>bcryptjs</code>. All entity IDs are UUIDs via
(auto-created on first run). Auth is handled by <code>rokojori-auth</code>
at <code>account.rokojori.com</code>; Roject verifies the shared
<code>accessToken</code> JWT cookie using <code>jsonwebtoken</code> +
<code>cookie-parser</code>. All entity IDs are UUIDs via
<code>crypto.randomUUID()</code> — no central counter, safe for parallel
instances. Start the server with <code>npm start</code>.
</p>
@ -311,8 +307,8 @@
<span class="tag">Node.js</span>
<span class="tag">Express</span>
<span class="tag">ts-node</span>
<span class="tag">express-session</span>
<span class="tag">bcryptjs</span>
<span class="tag">jsonwebtoken</span>
<span class="tag">cookie-parser</span>
<span class="tag">UUID IDs</span>
</div>
</div>