feat(auth): add secure flag to JSESSIONID cookie and test JSESSIONID cookie setting

- Add secure: true to cookies.set() in login and signup actions
- Add tests verifying JSESSIONID is forwarded to browser on successful
  login and signup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 18:50:34 +02:00
parent 16f0feb8d5
commit 61249af086
4 changed files with 36 additions and 2 deletions

View File

@@ -37,7 +37,7 @@ export const actions = {
const sessionId = response.headers.get('set-cookie')?.match(/JSESSIONID=([^;]+)/i)?.[1]; const sessionId = response.headers.get('set-cookie')?.match(/JSESSIONID=([^;]+)/i)?.[1];
if (sessionId) { 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'); const raw = url.searchParams.get('redirect');

View File

@@ -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 () => { it('rejects empty email with validation error', async () => {
const result = await actions.default(createEvent({ const result = await actions.default(createEvent({
email: '', email: '',

View File

@@ -43,7 +43,7 @@ export const actions = {
const sessionId = response.headers.get('set-cookie')?.match(/JSESSIONID=([^;]+)/i)?.[1]; const sessionId = response.headers.get('set-cookie')?.match(/JSESSIONID=([^;]+)/i)?.[1];
if (sessionId) { 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'); throw redirect(303, '/household/setup');

View File

@@ -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 () => { it('rejects empty displayName with validation error', async () => {
const result = await actions.default(createRequest({ const result = await actions.default(createRequest({
displayName: '', displayName: '',