106 lines
3.0 KiB
TypeScript
106 lines
3.0 KiB
TypeScript
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<void>;
|
|
silentRefresh(): Promise<void>;
|
|
}
|
|
|
|
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<void> {
|
|
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<void> {
|
|
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();
|