veza/apps/web/src/services/tokenStorage.ts

108 lines
4 KiB
TypeScript
Raw Normal View History

/**
* TokenStorage - Service de gestion du stockage des tokens
* T0169: Service simple pour stocker, récupérer et supprimer les tokens d'authentification
*
* SECURITY: Migration vers cookies httpOnly COMPLÉTÉE (Action 5.1.1.2)
* - Access Token: Stocké dans un cookie httpOnly par le backend (pas accessible via JavaScript)
* - Refresh Token: Stocké dans un cookie httpOnly par le backend (pas accessible via JavaScript)
*
* IMPORTANT: Les tokens sont maintenant dans des cookies httpOnly set par le backend.
* JavaScript ne peut pas accéder aux cookies httpOnly, donc cette classe est maintenant
* principalement une API de compatibilité (no-op).
*
* NOTE: Les cookies httpOnly sont automatiquement envoyés avec les requêtes via withCredentials: true.
* Le backend lit les tokens depuis les cookies, pas depuis localStorage ou les headers Authorization.
*/
const ACCESS_TOKEN_KEY = 'veza_access_token';
const REFRESH_TOKEN_KEY = 'veza_refresh_token';
/**
* Réinitialise le stockage (utile pour les tests)
* @internal
*/
export function _resetTokenMemory(): void {
// No-op: tokens are in httpOnly cookies, not accessible from JS
}
/**
* Classe TokenStorage pour gérer le stockage des tokens
* T0169: Service de gestion du stockage tokens
*
* SECURITY: Action 5.1.1.2 - Tokens sont maintenant dans des cookies httpOnly
* Cette classe est maintenant principalement une API de compatibilité (no-op)
* car les cookies httpOnly ne sont pas accessibles via JavaScript.
*/
export class TokenStorage {
/**
* Stocke les tokens d'authentification
* SECURITY: Action 5.1.1.2 - No-op car les tokens sont dans des cookies httpOnly
* Le backend sette les cookies httpOnly lors du login/register/refresh.
*
* @param accessToken - Token d'accès JWT (ignoré, dans cookie httpOnly)
* @param refreshToken - Token de rafraîchissement (ignoré, dans cookie httpOnly)
*/
static setTokens(_accessToken: string, _refreshToken: string): void {
// No-op: tokens are set in httpOnly cookies by backend, not accessible to JS
// Clean up any legacy localStorage tokens if they exist
try {
localStorage.removeItem(ACCESS_TOKEN_KEY);
localStorage.removeItem(REFRESH_TOKEN_KEY);
} catch {
// Ignore errors (e.g., in SSR environment)
}
}
/**
* Récupère le token d'accès
* SECURITY: Action 5.1.1.2 - Retourne null car le token est dans un cookie httpOnly
* Les cookies httpOnly ne sont pas accessibles via JavaScript.
*
* @returns null (token est dans cookie httpOnly, non accessible)
*/
static getAccessToken(): string | null {
// Token is in httpOnly cookie, not accessible from JavaScript
return null;
}
/**
* Récupère le token de rafraîchissement
* SECURITY: Action 5.1.1.2 - Retourne null car le token est dans un cookie httpOnly
* Les cookies httpOnly ne sont pas accessibles via JavaScript.
*
* @returns null (token est dans cookie httpOnly, non accessible)
*/
static getRefreshToken(): string | null {
// Token is in httpOnly cookie, not accessible from JavaScript
return null;
}
/**
* Supprime tous les tokens
* SECURITY: Action 5.1.1.2 - Nettoie seulement localStorage legacy si présent
* Les cookies httpOnly sont supprimés par le backend lors du logout.
*/
static clearTokens(): void {
// Clean up any legacy localStorage tokens if they exist
try {
localStorage.removeItem(ACCESS_TOKEN_KEY);
localStorage.removeItem(REFRESH_TOKEN_KEY);
} catch {
// Ignore errors (e.g., in SSR environment)
}
// Cookies httpOnly are cleared by backend on logout
}
/**
* Vérifie si des tokens sont présents
* SECURITY: Action 5.1.1.2 - Retourne false car on ne peut pas vérifier les cookies httpOnly
* Les cookies httpOnly ne sont pas accessibles via JavaScript.
*
* @returns false (ne peut pas vérifier les cookies httpOnly depuis JS)
*/
static hasTokens(): boolean {
// Cannot check httpOnly cookies from JavaScript
return false;
}
}