platform-codebase/@packages/@providers/auth-provider/src/auth-storage.ts
2026-01-18 09:20:17 -08:00

139 lines
3.3 KiB
TypeScript
Executable file

/**
* Token storage utilities for managing JWT tokens in localStorage
* Provides a centralized API for token management across the application
*
* All methods are SSR-safe and will return null/false/undefined in SSR context
*/
const ACCESS_TOKEN_KEY = 'auth_token';
const REFRESH_TOKEN_KEY = 'refresh_token';
/**
* Check if we're in a browser environment
*/
function isBrowser(): boolean {
return typeof window !== 'undefined';
}
export const authStorage = {
/**
* Get the access token from localStorage
*/
getAccessToken(): string | null {
if (!isBrowser()) return null;
return localStorage.getItem(ACCESS_TOKEN_KEY);
},
/**
* Set the access token in localStorage
*/
setAccessToken(token: string): void {
if (!isBrowser()) return;
localStorage.setItem(ACCESS_TOKEN_KEY, token);
},
/**
* Get the refresh token from localStorage
*/
getRefreshToken(): string | null {
if (!isBrowser()) return null;
return localStorage.getItem(REFRESH_TOKEN_KEY);
},
/**
* Set the refresh token in localStorage
*/
setRefreshToken(token: string): void {
if (!isBrowser()) return;
localStorage.setItem(REFRESH_TOKEN_KEY, token);
},
/**
* Set both tokens at once (used after login/register/refresh)
*/
setTokens(accessToken: string, refreshToken: string): void {
this.setAccessToken(accessToken);
this.setRefreshToken(refreshToken);
},
/**
* Remove the access token from localStorage
*/
removeAccessToken(): void {
if (!isBrowser()) return;
localStorage.removeItem(ACCESS_TOKEN_KEY);
},
/**
* Remove the refresh token from localStorage
*/
removeRefreshToken(): void {
if (!isBrowser()) return;
localStorage.removeItem(REFRESH_TOKEN_KEY);
},
/**
* Remove all auth tokens from localStorage (used on logout)
*/
clearTokens(): void {
this.removeAccessToken();
this.removeRefreshToken();
},
/**
* Check if user has valid tokens
*/
hasTokens(): boolean {
if (!isBrowser()) return false;
return !!this.getAccessToken() && !!this.getRefreshToken();
},
/**
* Decode JWT token payload (without verification - for client-side only)
* Returns null if token is invalid or expired
*/
decodeToken(token: string): Record<string, any> | null {
try {
const parts = token.split('.');
if (parts.length !== 3) {
return null;
}
const payload = JSON.parse(atob(parts[1]!));
// Check if token is expired
if (payload.exp && payload.exp * 1000 < Date.now()) {
return null;
}
return payload;
} catch {
return null;
}
},
/**
* Get token expiration time in milliseconds
*/
getTokenExpiration(token: string): number | null {
const payload = this.decodeToken(token);
return payload?.exp ? payload.exp * 1000 : null;
},
/**
* Check if access token is expired or will expire soon (within 1 minute)
*/
isAccessTokenExpired(): boolean {
const token = this.getAccessToken();
if (!token) return true;
const expiration = this.getTokenExpiration(token);
if (!expiration) return true;
const now = Date.now();
const oneMinute = 60 * 1000;
// Consider token expired if it expires within 1 minute
return expiration - now < oneMinute;
},
};