import { AxiosError } from "axios"; import { tokenManager } from "../lib/token-manager"; const ENDPOINT = { USER_SERVICE: { LOGIN: "/user-service/login", USERS: "/user-service/api/v1/users", SILENT_REFRESH: "/user-service/api/v1/users/token/refresh", AUTHORIZATIONS: "/user-service/api/v1/authorizations", ROLE_AUTHORIZATIONS: "/user-service/api/v1/role-authorizations", }, }; const JWT_EXPIRATION_TIME = 1800000; const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token"; export interface ILogin { userId: string; password: string; } export interface LoginService { login(payload: ILogin): Promise; silentRefresh(): Promise; } export class LoginApiService implements LoginService { private static instance: LoginApiService; private constructor() {} public static getInstance(): LoginApiService { if (!LoginApiService.instance) { LoginApiService.instance = new LoginApiService(); } return LoginApiService.instance; } public async login(payload: ILogin): Promise { try { const response = await fetch(`/api/proxy${ENDPOINT.USER_SERVICE.LOGIN}`, { method: "POST", body: JSON.stringify({ userId: payload.userId, password: payload.password, }), }); const data = await response.json(); const accessToken = data[ACCESS_TOKEN]; const tokenId = data[AUTH_USER_ID]; if (!accessToken || !tokenId) { throw new Error("Missing required authentication tokens"); } tokenManager.setToken(CLAIM_NAME, accessToken); tokenManager.setToken(AUTH_USER_ID, tokenId); tokenManager.setupRefreshTimer( () => this.silentRefresh(), JWT_EXPIRATION_TIME, ); } catch (error) { if (error instanceof AxiosError) { throw new Error(`Login failed: ${error.response?.data?.message}`); } throw new Error(`Login failed: ${error}`); } } public async silentRefresh(): Promise { try { const response = await fetch( `/api/proxy${ENDPOINT.USER_SERVICE.SILENT_REFRESH}`, { method: "PUT", }, ); const data = await response.json(); const accessToken = response.headers.get("access-token"); const tokenId = response.headers.get("token-id"); if (!accessToken || !tokenId) { throw new Error("Missing required authentication tokens"); } tokenManager.setToken(CLAIM_NAME, accessToken); tokenManager.setToken(AUTH_USER_ID, tokenId); } catch (error) { tokenManager.clearAuthToken(); if (error instanceof AxiosError) { throw new Error( `Silent refresh failed: ${error.response?.data?.message}`, ); } throw new Error(`Silent refresh failed: ${error}`); } } } export const LoginApi = LoginApiService.getInstance();