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
JavaScript
/**
* @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]);
};