[object Object]

← back to NationalPaperHangers

auth: regenerate session on OAuth sign-in (fixation defense — match claim.js)

f240b01e8c3c1cd91a5480ef4a9b87bfad84ce8b · 2026-05-06 11:11:42 -0700 · Steve

Files touched

Diff

commit f240b01e8c3c1cd91a5480ef4a9b87bfad84ce8b
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed May 6 11:11:42 2026 -0700

    auth: regenerate session on OAuth sign-in (fixation defense — match claim.js)
---
 routes/auth-google.js   | 12 +++++++++++-
 routes/auth-linkedin.js |  9 ++++++++-
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/routes/auth-google.js b/routes/auth-google.js
index 64f2c5b..845f345 100644
--- a/routes/auth-google.js
+++ b/routes/auth-google.js
@@ -18,6 +18,15 @@ const db = require('../lib/db');
 
 const router = express.Router();
 
+// Match the installer-auth pattern in claim.js — regenerate session on sign-in
+// so a hijacked pre-auth session ID can't ride through to the authenticated
+// identity (session-fixation defense).
+function regenerateSession(req) {
+  return new Promise((resolve, reject) => {
+    req.session.regenerate(err => err ? reject(err) : resolve());
+  });
+}
+
 const CLIENT_ID = process.env.NPH_GOOGLE_OAUTH_CLIENT_ID || '';
 const CLIENT_SECRET = process.env.NPH_GOOGLE_OAUTH_CLIENT_SECRET || '';
 const SCOPE = 'openid email profile';
@@ -165,9 +174,10 @@ router.get('/auth/google/callback', async (req, res, next) => {
       );
       id = ins.id;
     }
+    // Regenerate before assigning the authenticated identity (session fixation).
+    await regenerateSession(req);
     req.session.consumerAccountId = id;
     req.session.consumer = { id, email: profile.email, name: profile.name || null, picture_url: profile.picture || null };
-    req.session.gOAuth = null;
     res.redirect(sessionNext);
   } catch (err) { next(err); }
 });
diff --git a/routes/auth-linkedin.js b/routes/auth-linkedin.js
index 96ca322..9a3f2f4 100644
--- a/routes/auth-linkedin.js
+++ b/routes/auth-linkedin.js
@@ -22,6 +22,13 @@ const db = require('../lib/db');
 
 const router = express.Router();
 
+// Session-fixation defense — match claim.js + auth-google.js pattern.
+function regenerateSession(req) {
+  return new Promise((resolve, reject) => {
+    req.session.regenerate(err => err ? reject(err) : resolve());
+  });
+}
+
 const CLIENT_ID = process.env.LINKEDIN_CLIENT_ID || '';
 const CLIENT_SECRET = process.env.LINKEDIN_CLIENT_SECRET || '';
 const SCOPE = 'openid profile email';
@@ -164,9 +171,9 @@ router.get('/auth/linkedin/callback', async (req, res, next) => {
       );
       id = ins.id;
     }
+    await regenerateSession(req);
     req.session.consumerAccountId = id;
     req.session.consumer = { id, email: profile.email, name: profile.name || null, picture_url: profile.picture || null, provider: 'linkedin' };
-    req.session.liOAuth = null;
     res.redirect(sessionNext);
   } catch (err) { next(err); }
 });

← f65e1d4 fix(public/installer): coerce market_segments/materials elem  ·  back to NationalPaperHangers  ·  watch the work: YT + IG reels + TikTok embeds via partial ac a9f49d0 →