fix(auth): logout actually clears the session cookie in Chrome
All checks were successful
Deploy to Production / deploy (push) Successful in 53s
All checks were successful
Deploy to Production / deploy (push) Successful in 53s
The clearCookie call on /v1/auth/logout was passing only {path:'/'},
missing the httpOnly + sameSite + secure flags the setCookie used. In
production (secure=true), Chrome treats a Set-Cookie clear directive
without Secure as a *different* cookie — it creates an empty insecure
cookie and leaves the original Secure session cookie in place. Result:
users who clicked "Sign out" stayed logged in for the full 30-day
session lifetime in the browser's view (DB session was destroyed
correctly; only the cookie persisted).
Now both setCookie and clearCookie pull from sessionCookieOpts() so
the attributes can't drift apart again.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
091454d273
commit
1cccdbdff1
@ -20,6 +20,29 @@ import { sendSms, smsConfigured } from '../lib/sms.js';
|
||||
const SESSION_COOKIE = 'bmm_session';
|
||||
const OAUTH_STATE_COOKIE = 'bmm_oauth_state';
|
||||
|
||||
/**
|
||||
* Single source of truth for the session cookie's flags. setCookie AND
|
||||
* clearCookie MUST agree on (path, sameSite, secure, httpOnly) — when they
|
||||
* drift, Chrome treats the clear directive as a brand-new cookie with
|
||||
* different security attributes and silently leaves the original one in
|
||||
* place. That's what bit us until now: logout looked successful (200 OK
|
||||
* with a Set-Cookie clear) but the real session cookie persisted because
|
||||
* the clear omitted Secure+HttpOnly.
|
||||
*/
|
||||
function sessionCookieOpts(): {
|
||||
httpOnly: true;
|
||||
sameSite: 'lax';
|
||||
path: '/';
|
||||
secure: boolean;
|
||||
} {
|
||||
return {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: config.NODE_ENV === 'production',
|
||||
};
|
||||
}
|
||||
|
||||
const GoogleClaims = z.object({
|
||||
iss: z.string(),
|
||||
aud: z.string(),
|
||||
@ -229,7 +252,7 @@ export async function authRoutes(app: FastifyInstance): Promise<void> {
|
||||
const token = req.cookies[SESSION_COOKIE];
|
||||
const session = token ? await getSession(token) : null;
|
||||
if (token) await destroySession(token);
|
||||
reply.clearCookie(SESSION_COOKIE, { path: '/' });
|
||||
reply.clearCookie(SESSION_COOKIE, sessionCookieOpts());
|
||||
if (session) {
|
||||
await audit({
|
||||
orgId: session.orgId,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user