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.
This commit is contained in:
2026-05-01 21:30:52 -05:00
parent 2fbd476145
commit a5b378ccff
31 changed files with 256 additions and 91 deletions

View File

@@ -0,0 +1,55 @@
import type { Cookies } from '@sveltejs/kit';
import {
ACCESS_TOKEN_CHUNK_COUNT,
accessTokenChunkName,
splitAccessTokenForCookies,
ACCESS_TOKEN_MAX_CHUNKS
} from '$lib/access-token-cookie.shared';
export function getAccessTokenFromCookies(cookies: Cookies): string | null {
const countRaw = cookies.get(ACCESS_TOKEN_CHUNK_COUNT);
if (countRaw) {
const n = parseInt(countRaw, 10);
if (!Number.isFinite(n) || n < 1 || n > ACCESS_TOKEN_MAX_CHUNKS) return null;
let out = '';
for (let i = 0; i < n; i++) {
const p = cookies.get(accessTokenChunkName(i));
if (p == null) return null;
out += p;
}
return out;
}
return cookies.get('access_token') ?? null;
}
export function clearAccessTokenCookies(cookies: Cookies) {
cookies.delete('access_token', { path: '/' });
cookies.delete(ACCESS_TOKEN_CHUNK_COUNT, { path: '/' });
for (let i = 0; i < ACCESS_TOKEN_MAX_CHUNKS; i++) {
cookies.delete(accessTokenChunkName(i), { path: '/' });
}
}
export function setAccessTokenCookies(
cookies: Cookies,
token: string,
opts: { secure: boolean; maxAge: number }
) {
clearAccessTokenCookies(cookies);
const split = splitAccessTokenForCookies(token);
const base = {
path: '/',
httpOnly: false as const,
sameSite: 'lax' as const,
secure: opts.secure,
maxAge: opts.maxAge
};
if (split.kind === 'single') {
cookies.set('access_token', split.value, base);
return;
}
cookies.set(ACCESS_TOKEN_CHUNK_COUNT, String(split.parts.length), base);
split.parts.forEach((part, i) => {
cookies.set(accessTokenChunkName(i), part, base);
});
}

View File

@@ -4,6 +4,11 @@
*/
import { redirect, type Cookies } from '@sveltejs/kit';
import {
clearAccessTokenCookies,
getAccessTokenFromCookies,
setAccessTokenCookies
} from '$lib/server/access-token-cookie';
/**
* Obtiene y normaliza la URL base de la API para llamadas desde el servidor
@@ -34,7 +39,7 @@ export function getServerApiUrl(): string {
*/
export function getAuthTokens(cookies: Cookies) {
return {
accessToken: cookies.get('access_token'),
accessToken: getAccessTokenFromCookies(cookies),
refreshToken: cookies.get('refresh_token')
};
}
@@ -43,7 +48,7 @@ export function getAuthTokens(cookies: Cookies) {
* Establece los tokens de autenticación en las cookies
*
* Política de seguridad:
* - access_token → NO HttpOnly (el cliente necesita incluirlo en el header Authorization)
* - access_token → NO HttpOnly (Bearer desde JS); si el JWT es muy grande, varias cookies fragmentadas
* - refresh_token → HttpOnly=true (JS nunca lo lee; el servidor lo maneja via /api-sveltekit/auth/silent-refresh)
*/
export function setAuthTokens(
@@ -51,10 +56,7 @@ export function setAuthTokens(
accessToken: string,
refreshToken?: string
) {
cookies.set('access_token', accessToken, {
path: '/',
httpOnly: false, // El cliente JS necesita leerlo para el header Bearer
sameSite: 'lax',
setAccessTokenCookies(cookies, accessToken, {
secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60 * 24 * 7 // 7 días
});
@@ -74,7 +76,7 @@ export function setAuthTokens(
* Limpia todos los tokens de autenticación de las cookies
*/
export function clearAuthTokens(cookies: Cookies) {
cookies.delete('access_token', { path: '/' });
clearAccessTokenCookies(cookies);
cookies.delete('refresh_token', { path: '/' });
cookies.delete('active_company_id', { path: '/' });
}