fix(web): move redirect() outside try/catch in changePasswordAction
Tessera CI/CD / Lint & Type Check (push) Successful in 40s
Tessera CI/CD / Tests (push) Successful in 40s
Tessera CI/CD / Build & Publish Images (push) Successful in 1m27s

redirect() throws NEXT_REDIRECT internally — inside catch it was swallowed
and returned networkError. Extract cookie data in try/catch, then set
cookie and redirect() after the block so the throw propagates correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 07:25:57 +02:00
parent f4ece4890d
commit 40c4876a19
+18 -14
View File
@@ -112,6 +112,9 @@ export async function changePasswordAction(
return { success: false, error: 'networkError' }; return { success: false, error: 'networkError' };
} }
let newSessionToken: string | undefined;
let newSessionMaxAge: number | undefined;
try { try {
const response = await fetch(`${API_URL}/auth/change-password`, { const response = await fetch(`${API_URL}/auth/change-password`, {
method: 'POST', method: 'POST',
@@ -122,38 +125,39 @@ export async function changePasswordAction(
body: JSON.stringify({ currentPassword, newPassword }), body: JSON.stringify({ currentPassword, newPassword }),
}); });
console.log('[changePasswordAction] API response status:', response.status);
if (!response.ok) { if (!response.ok) {
const data = await response.json().catch(() => null); const data = await response.json().catch(() => null);
console.error('[changePasswordAction] API error:', data);
if (data?.message === 'Current password is incorrect') { if (data?.message === 'Current password is incorrect') {
return { success: false, error: 'wrongCurrentPassword' }; return { success: false, error: 'wrongCurrentPassword' };
} }
return { success: false, error: 'networkError' }; return { success: false, error: 'networkError' };
} }
// Forward new session cookie from API (mustChangePassword=false baked in)
const setCookieHeader = response.headers.get('set-cookie'); const setCookieHeader = response.headers.get('set-cookie');
if (setCookieHeader) { if (setCookieHeader) {
const sessionMatch = setCookieHeader.match(/session=([^;]+)/); const sessionMatch = setCookieHeader.match(/session=([^;]+)/);
if (sessionMatch) {
const maxAgeMatch = setCookieHeader.match(/Max-Age=(\d+)/i); const maxAgeMatch = setCookieHeader.match(/Max-Age=(\d+)/i);
cookieStore.set('session', sessionMatch[1], { if (sessionMatch) {
httpOnly: true, newSessionToken = sessionMatch[1];
secure: process.env.NODE_ENV === 'production', newSessionMaxAge = maxAgeMatch ? parseInt(maxAgeMatch[1]) : undefined;
sameSite: 'lax',
path: '/',
...(maxAgeMatch ? { maxAge: parseInt(maxAgeMatch[1]) } : {}),
});
} }
} }
redirect('/');
} catch (err) { } catch (err) {
console.error('[changePasswordAction] fetch threw:', err); console.error('[changePasswordAction] fetch threw:', err);
return { success: false, error: 'networkError' }; return { success: false, error: 'networkError' };
} }
if (newSessionToken) {
cookieStore.set('session', newSessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
...(newSessionMaxAge ? { maxAge: newSessionMaxAge } : {}),
});
}
redirect('/');
} }
/** /**