fix(auth): remove manual session.save() — was suppressing Set-Cookie header

Login was returning 200 + correct user JSON + writing a row to the
sessions table, but emitting zero Set-Cookie headers. Root cause:

  session.regenerate() → set fields → session.save() → res.json()

Calling session.save() manually writes the store but bypasses
express-session's res.end() hook, which is the only path that adds
the Set-Cookie header to the response. The cookie was never sent to
the browser even though the session existed server-side — hence the
redirect loop.

Fix: remove the manual save(). Set the session fields and call
res.json() directly inside regenerate()'s callback; express-session
handles store write + Set-Cookie automatically on res.end().
This commit is contained in:
opencode 2026-05-27 02:59:15 +00:00 committed by ZGaetano
parent 5de1e3dc3d
commit e71c330bdd

View file

@ -127,10 +127,11 @@ router.post('/login', async (req, res, next) => {
// Successful login — clear any accumulated failed attempts
clearAttempts(req, username);
// Regenerate session ID to prevent fixation attacks.
// Explicit save() + log on success/failure so a broken session store
// (missing table, PG read-only, etc.) doesn't silently 200 with no
// persisted session — the symptom that caused the redirect loop.
// Regenerate session ID to prevent fixation attacks, then let
// express-session write Set-Cookie on its own res.end() hook.
// Do NOT call session.save() manually — that writes the store but
// bypasses the middleware's header-writing path, which is why the
// Set-Cookie header was missing even though the session row existed.
req.session.regenerate((err) => {
if (err) {
console.error('[auth] session.regenerate failed:', err);
@ -139,18 +140,12 @@ router.post('/login', async (req, res, next) => {
req.session.userId = user.id;
req.session.username = user.username;
req.session.role = user.role;
req.session.save((saveErr) => {
if (saveErr) {
console.error('[auth] session.save failed:', saveErr);
return next(saveErr);
}
console.log(`[auth] login ok user=${user.username} sid=${req.sessionID?.slice(0,8) || '?'} secure=${req.secure} proto=${req.protocol}`);
res.json({
id: user.id,
username: user.username,
display_name: user.display_name,
role: user.role,
});
console.log(`[auth] login ok user=${user.username} sid=${req.sessionID?.slice(0,8) || '?'} secure=${req.secure} proto=${req.protocol}`);
res.json({
id: user.id,
username: user.username,
display_name: user.display_name,
role: user.role,
});
});
} catch (err) {