/** * Local Token Storage * * Implements TokenStorage interface using localStorage. * Provides secure token management for authentication. * * @layer Infrastructure - Storage */ import type { TokenStorage } from '../http/api/shared/types'; import { decodeJwt } from '@/lib/jwt'; const ACCESS_TOKEN_KEY = 'archer_access_token'; const REFRESH_TOKEN_KEY = 'archer_refresh_token'; const USER_DATA_KEY = 'archer_user'; /** * Stored user data structure */ export interface StoredUserData { id: string; email: string; name: string; companyId: string; role: string; authOrigin?: string; } /** * LocalTokenStorage * * localStorage-based implementation of TokenStorage. * Stores access and refresh tokens for session management. */ export class LocalTokenStorage implements TokenStorage { /** * Get access token from localStorage */ getAccessToken(): string | null { return localStorage.getItem(ACCESS_TOKEN_KEY); } /** * Get refresh token from localStorage */ getRefreshToken(): string | null { return localStorage.getItem(REFRESH_TOKEN_KEY); } /** * Set both tokens in localStorage */ setTokens(accessToken: string, refreshToken: string): void { localStorage.setItem(ACCESS_TOKEN_KEY, accessToken); localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken); } /** * Remove all tokens and user data (logout) */ removeTokens(): void { localStorage.removeItem(ACCESS_TOKEN_KEY); localStorage.removeItem(REFRESH_TOKEN_KEY); localStorage.removeItem(USER_DATA_KEY); } /** * Check if tokens exist */ hasTokens(): boolean { return !!(this.getAccessToken() && this.getRefreshToken()); } /** * Store user data */ setUser(user: StoredUserData): void { localStorage.setItem(USER_DATA_KEY, JSON.stringify(user)); } /** * Get stored user data */ getUser(): StoredUserData | null { const data = localStorage.getItem(USER_DATA_KEY); if (!data) return null; try { return JSON.parse(data) as StoredUserData; } catch { return null; } } /** * Get current user's company ID */ getCompanyId(): string | null { return this.getUser()?.companyId ?? null; } /** * Get plan capabilities decoded from the JWT access token */ getCapabilities(): Record { const token = this.getAccessToken(); if (!token) return {}; const payload = decodeJwt(token); return payload?.capabilities ?? {}; } /** * Get a specific capability value */ getCapability(key: string): string | undefined { return this.getCapabilities()[key]; } } /** * Singleton instance of LocalTokenStorage */ export const tokenStorage = new LocalTokenStorage();