Files
plantillas-proyectos/frontend/src/routes/api-sveltekit/auth/silent-refresh/+server.ts
AlexeerCT a5b378ccff refactor: centralize access token handling in cookies and improve related functions
- Introduced utility functions for managing access tokens in cookies, including setting, getting, and clearing tokens.
- Updated various components and server routes to utilize the new access token functions for better consistency and maintainability.
- Removed redundant cookie handling code across the application, streamlining the authentication process.
2026-05-01 21:30:52 -05:00

63 lines
2.3 KiB
TypeScript

/**
* 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 });
}
};