UNPKG

pagamio-frontend-commons-lib

Version:

Pagamio library for Frontend reusable components like the form engine and table container

172 lines (171 loc) 5.74 kB
/** * @fileoverview Token management utility for handling authentication tokens */ import Cookies from 'js-cookie'; import { useMemo } from 'react'; const TOKEN_CONFIG = { ACCESS_TOKEN: { name: 'accessToken', defaultExpiry: 1 / 24, path: '/', secure: true, sameSite: 'strict', }, REFRESH_TOKEN: { name: 'refreshToken', defaultExpiry: 7, path: '/', secure: true, sameSite: 'strict', }, }; export class TokenManager { cookieOptions; baseUrl; refreshEndpoint; constructor(config) { this.cookieOptions = { secure: true, sameSite: 'strict', path: '/', ...config.cookieOptions, }; this.baseUrl = config.baseUrl; this.refreshEndpoint = config.refreshEndpoint; } setAccessToken(tokenInfo) { const expiryInDays = tokenInfo.expiresIn / (24 * 3600); this.setCookie(TOKEN_CONFIG.ACCESS_TOKEN.name, tokenInfo.token, { expires: expiryInDays, }); const expiresAt = Date.now() + tokenInfo.expiresIn * 1000; this.setCookie(`${TOKEN_CONFIG.ACCESS_TOKEN.name}ExpiresAt`, String(expiresAt), { expires: expiryInDays, }); } getAccessToken() { const token = this.getCookie(TOKEN_CONFIG.ACCESS_TOKEN.name); const expiresAtStr = this.getCookie(`${TOKEN_CONFIG.ACCESS_TOKEN.name}ExpiresAt`); const expiresAt = expiresAtStr ? parseInt(expiresAtStr, 10) : null; return { token, expiresAt }; } setRefreshToken(tokenInfo) { const expiryInDays = tokenInfo.expiresIn / (24 * 3600); this.setCookie(TOKEN_CONFIG.REFRESH_TOKEN.name, tokenInfo.token, { expires: expiryInDays, }); } getRefreshToken() { return this.getCookie(TOKEN_CONFIG.REFRESH_TOKEN.name); } async refreshTokens() { try { const oldRefreshToken = this.getRefreshToken(); if (!oldRefreshToken) { this.clearAllTokens(); throw new Error('No refresh token available'); } const response = await fetch(`${this.baseUrl}${this.refreshEndpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refreshToken: oldRefreshToken }), }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Failed to refresh token'); } const { accessToken, refreshToken: newRefreshToken, accessTokenExpiresIn, refreshTokenExpiresIn } = data; this.handleAuthTokens({ accessToken: { token: accessToken, expiresIn: accessTokenExpiresIn, }, ...(newRefreshToken && refreshTokenExpiresIn ? { refreshToken: { token: newRefreshToken, expiresIn: refreshTokenExpiresIn, }, } : {}), }); return true; } catch (error) { console.error('Token refresh failed:', error); this.clearAllTokens(); return false; } } /** * Handles setting both access and refresh tokens with proper expiry */ handleSetAccessAndRefreshTokens(accessToken, refreshToken, accessTokenExpiresIn, refreshTokenExpiresIn) { // Set access token this.handleAuthTokens({ accessToken: { token: accessToken, expiresIn: accessTokenExpiresIn, }, ...(refreshToken && refreshTokenExpiresIn ? { refreshToken: { token: refreshToken, expiresIn: refreshTokenExpiresIn, }, } : {}), }); } clearAllTokens() { this.removeCookie(TOKEN_CONFIG.ACCESS_TOKEN.name); this.removeCookie(`${TOKEN_CONFIG.ACCESS_TOKEN.name}ExpiresAt`); this.removeCookie(TOKEN_CONFIG.REFRESH_TOKEN.name); } isAccessTokenExpired() { const { expiresAt } = this.getAccessToken(); if (!expiresAt) return true; return Date.now() >= expiresAt - 30000; } handleAuthTokens(authResponse) { this.setAccessToken(authResponse.accessToken); if (authResponse.refreshToken) { this.setRefreshToken(authResponse.refreshToken); } } setCookie(name, value, options = {}) { if (typeof window === 'undefined') return; const finalOptions = { ...this.cookieOptions, ...options, }; try { Cookies.set(name, value, finalOptions); } catch (error) { console.error(`Error setting cookie ${name}:`, error); } } getCookie(name) { if (typeof window === 'undefined') return undefined; return Cookies.get(name); } removeCookie(name, options = {}) { if (typeof window === 'undefined') return; Cookies.remove(name, { ...this.cookieOptions, ...options }); } } // Standalone token manager instance creation export const createTokenManager = (config) => { return new TokenManager(config); }; // React hook for using token manager export const useTokenManager = (config) => { return useMemo(() => new TokenManager(config), [config]); };