From 81711f1f0922960ca3195fa0a60bced93998d27a Mon Sep 17 00:00:00 2001 From: Alexander Bocken Date: Fri, 20 Mar 2026 16:25:51 +0100 Subject: [PATCH] fix: cache auth session on locals to prevent cookies.set after response The authorization hook already calls locals.auth() which can set cookies. Layout server loads calling auth() again caused a race where cookies.set() fired after the response started streaming. Now the hook stashes the session on locals.session and all layouts reuse it. --- src/app.d.ts | 1 + src/hooks.server.ts | 3 ++- src/routes/(main)/+layout.server.ts | 2 +- src/routes/[faithLang=faithLang]/+layout.server.ts | 2 +- src/routes/[recipeLang=recipeLang]/+layout.server.ts | 2 +- src/routes/cospend/+layout.server.ts | 2 +- src/routes/fitness/+layout.server.ts | 2 +- 7 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/app.d.ts b/src/app.d.ts index e6d550a..cc6b1ab 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -12,6 +12,7 @@ declare global { } interface Locals { auth(): Promise; + session?: Session | null; } // interface PageData {} interface PageState { diff --git a/src/hooks.server.ts b/src/hooks.server.ts index ca8f849..29a5cb1 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -20,7 +20,8 @@ await dbConnect().then(() => { async function authorization({ event, resolve }: Parameters[0]) { const session = await event.locals.auth(); - + event.locals.session = session; + // Protect rezepte routes if (event.url.pathname.startsWith('/rezepte/edit') || event.url.pathname.startsWith('/rezepte/add')) { if (!session) { diff --git a/src/routes/(main)/+layout.server.ts b/src/routes/(main)/+layout.server.ts index c8a95cd..c0c2b24 100644 --- a/src/routes/(main)/+layout.server.ts +++ b/src/routes/(main)/+layout.server.ts @@ -2,6 +2,6 @@ import type { LayoutServerLoad } from "./$types" export const load : LayoutServerLoad = (async ({locals}) => { return { - session: await locals.auth(), + session: locals.session ?? await locals.auth(), } }); diff --git a/src/routes/[faithLang=faithLang]/+layout.server.ts b/src/routes/[faithLang=faithLang]/+layout.server.ts index dcd656f..9721499 100644 --- a/src/routes/[faithLang=faithLang]/+layout.server.ts +++ b/src/routes/[faithLang=faithLang]/+layout.server.ts @@ -10,7 +10,7 @@ export const load : LayoutServerLoad = async ({locals, params}) => { const lang = params.faithLang === 'faith' ? 'en' : 'de'; return { - session: await locals.auth(), + session: locals.session ?? await locals.auth(), lang, faithLang: params.faithLang } diff --git a/src/routes/[recipeLang=recipeLang]/+layout.server.ts b/src/routes/[recipeLang=recipeLang]/+layout.server.ts index 5911247..775b2fe 100644 --- a/src/routes/[recipeLang=recipeLang]/+layout.server.ts +++ b/src/routes/[recipeLang=recipeLang]/+layout.server.ts @@ -10,7 +10,7 @@ export const load : LayoutServerLoad = async ({locals, params}) => { const lang = params.recipeLang === 'recipes' ? 'en' : 'de'; return { - session: await locals.auth(), + session: locals.session ?? await locals.auth(), lang, recipeLang: params.recipeLang } diff --git a/src/routes/cospend/+layout.server.ts b/src/routes/cospend/+layout.server.ts index ed6565d..24581bd 100644 --- a/src/routes/cospend/+layout.server.ts +++ b/src/routes/cospend/+layout.server.ts @@ -2,6 +2,6 @@ import type { LayoutServerLoad } from "./$types" export const load : LayoutServerLoad = async ({locals}) => { return { - session: await locals.auth() + session: locals.session ?? await locals.auth() } }; diff --git a/src/routes/fitness/+layout.server.ts b/src/routes/fitness/+layout.server.ts index 4ec3500..18b1c23 100644 --- a/src/routes/fitness/+layout.server.ts +++ b/src/routes/fitness/+layout.server.ts @@ -2,6 +2,6 @@ import type { LayoutServerLoad } from './$types'; export const load: LayoutServerLoad = async ({ locals }) => { return { - session: await locals.auth() + session: locals.session ?? await locals.auth() }; };