diff --git a/frontend/src/routes/(public)/login/+page.server.ts b/frontend/src/routes/(public)/login/+page.server.ts index 9dc9b09..452e13f 100644 --- a/frontend/src/routes/(public)/login/+page.server.ts +++ b/frontend/src/routes/(public)/login/+page.server.ts @@ -37,7 +37,7 @@ export const actions = { const sessionId = response.headers.get('set-cookie')?.match(/JSESSIONID=([^;]+)/i)?.[1]; if (sessionId) { - cookies.set('JSESSIONID', sessionId, { path: '/', httpOnly: true, sameSite: 'lax' }); + cookies.set('JSESSIONID', sessionId, { path: '/', httpOnly: true, sameSite: 'lax', secure: true }); } const raw = url.searchParams.get('redirect'); diff --git a/frontend/src/routes/(public)/login/page.server.test.ts b/frontend/src/routes/(public)/login/page.server.test.ts index e143566..212aeaa 100644 --- a/frontend/src/routes/(public)/login/page.server.test.ts +++ b/frontend/src/routes/(public)/login/page.server.test.ts @@ -119,6 +119,23 @@ describe('login form action', () => { } }); + it('sets JSESSIONID cookie on successful login', async () => { + mockPost.mockResolvedValue({ + data: { data: { id: '123' } }, + error: undefined, + response: { headers: { get: vi.fn().mockReturnValue('JSESSIONID=abc123; Path=/; HttpOnly') } } + }); + + const event = createEvent({ email: 'sarah@example.com', password: 'password123' }); + try { + await actions.default(event); + } catch { + // redirect throws + } + + expect(event.cookies.set).toHaveBeenCalledWith('JSESSIONID', 'abc123', expect.objectContaining({ path: '/', secure: true })); + }); + it('rejects empty email with validation error', async () => { const result = await actions.default(createEvent({ email: '', diff --git a/frontend/src/routes/(public)/signup/+page.server.ts b/frontend/src/routes/(public)/signup/+page.server.ts index f158209..1c4f8ed 100644 --- a/frontend/src/routes/(public)/signup/+page.server.ts +++ b/frontend/src/routes/(public)/signup/+page.server.ts @@ -43,7 +43,7 @@ export const actions = { const sessionId = response.headers.get('set-cookie')?.match(/JSESSIONID=([^;]+)/i)?.[1]; if (sessionId) { - cookies.set('JSESSIONID', sessionId, { path: '/', httpOnly: true, sameSite: 'lax' }); + cookies.set('JSESSIONID', sessionId, { path: '/', httpOnly: true, sameSite: 'lax', secure: true }); } throw redirect(303, '/household/setup'); diff --git a/frontend/src/routes/(public)/signup/page.server.test.ts b/frontend/src/routes/(public)/signup/page.server.test.ts index b224db5..451497b 100644 --- a/frontend/src/routes/(public)/signup/page.server.test.ts +++ b/frontend/src/routes/(public)/signup/page.server.test.ts @@ -76,6 +76,23 @@ describe('signup form action', () => { } }); + it('sets JSESSIONID cookie on successful signup', async () => { + mockPost.mockResolvedValue({ + data: { data: { id: '123' } }, + error: undefined, + response: { headers: { get: vi.fn().mockReturnValue('JSESSIONID=xyz789; Path=/; HttpOnly') } } + }); + + const event = createRequest({ displayName: 'Sarah', email: 'sarah@example.com', password: 'password123' }); + try { + await actions.default(event); + } catch { + // redirect throws + } + + expect(event.cookies.set).toHaveBeenCalledWith('JSESSIONID', 'xyz789', expect.objectContaining({ path: '/', secure: true })); + }); + it('rejects empty displayName with validation error', async () => { const result = await actions.default(createRequest({ displayName: '',