/** * Endpoint server-side para el refresh silencioso del access token. * * Flujo de seguridad: * 1. El cliente llama a POST /api-sveltekit/auth/silent-refresh con credentials:'include' * (las cookies HttpOnly se envían automáticamente, sin que JS las lea). * 2. Este servidor lee el refresh_token de la cookie HttpOnly. * 3. Llama al backend FastAPI /v1/auth/refresh con el refresh_token. * 4. Si es exitoso, actualiza las cookies HttpOnly con los nuevos tokens. * 5. Retorna solo el access_token al cliente (el refresh_token permanece en HttpOnly). * * De este modo el refresh_token NUNCA toca el código JavaScript del cliente. */ import { json } from '@sveltejs/kit'; import type { RequestEvent } from '@sveltejs/kit'; import { getServerApiUrl, setAuthTokens } from '$lib/server/api'; import { clearAccessTokenCookies } from '$lib/server/access-token-cookie'; export const POST = async ({ cookies, fetch }: RequestEvent) => { const refreshToken = cookies.get('refresh_token'); if (!refreshToken) { return json({ error: 'No refresh token available' }, { status: 401 }); } try { const baseUrl = getServerApiUrl(); const response = await fetch(`${baseUrl}v1/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh_token: refreshToken }) }); if (!response.ok) { // El refresh token expiró o fue invalidado por Keycloak (sesión terminada). // Limpiar las cookies para que el servidor redirigir al login en la siguiente carga. cookies.delete('refresh_token', { path: '/' }); clearAccessTokenCookies(cookies); cookies.delete('active_company_id', { path: '/' }); const status = response.status === 401 ? 401 : 400; return json({ error: 'Refresh token expired or invalid' }, { status }); } const data = (await response.json()) as { access_token: string; refresh_token?: string; expires_in?: number; }; // Actualizar las cookies HttpOnly con los nuevos tokens setAuthTokens(cookies, data.access_token, data.refresh_token); // Devolver solo el access_token al cliente return json({ access_token: data.access_token }); } catch (error) { console.error('[silent-refresh] Error inesperado:', error); return json({ error: 'Internal server error' }, { status: 500 }); } };