Re-validate JWT against the DB in isLoggedIn (fixes #12) #16
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/stale-jwt-revalidation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fixes #12.
isLoggedIntrustedidandrolestraight from the JWT and never re-checked the database. Because the token embedsroleand lastsJWT_EXPIRES_IN(default1d):This also undercut the "cannot demote/delete the last admin" guards in
admin.controller.js, since the demoted/deleted admin still holds a valid token.What changed
server/src/utils/auth.jsisLoggedInis nowasyncand re-loads the user from the DB on every request:id;users.getById(decoded.id);401(deleted since the token was issued);req.userto the fresh DB row so the currentroleis always used downstream — the token payload'sroleis no longer trusted.500rather than falling through.const users = require('../model/users/users.model').Why this approach
/auth/mehandler already uses — so the authorization path now behaves consistently with the identity path.isLoggedInrather than per-route — every admin route already funnels throughisLoggedIn, so one change covers them all. This is an admin panel (low request volume), so one extra indexed lookup per request is a negligible cost for immediate revocation.req.userbecomes the sanitized DB row —getByIdalready strips the password hash and returns{ id, username, role, ... }. Every controller usesreq.user.id/.username/.role, all still present, so nothing downstream breaks.Scope / what was intentionally left alone
getUserFromRequest(token-only) is still used by the maintenance-mode bypass inmiddleware/siteMode.js. That path only decides whether a logged-in user can view the site during maintenance — not an access-control boundary — so it was left as-is to keep this change focused on the privilege path.Testing
node -csyntax check.require('./src/utils/auth')smoke test to confirm the newauth.js -> users.model -> users.dbrequire chain has no circular dependency and loads cleanly.Notes
Backend only, no schema/client changes. Independent of the companion PR for #10.