2026-03-06 17:54:09 +07:00
|
|
|
import axios from "@/config/axios";
|
2025-12-22 14:53:19 +07:00
|
|
|
import { API_ENDPOINTS } from "@/config/api";
|
2026-04-07 13:20:46 +07:00
|
|
|
import rawAxios from "axios";
|
2026-03-06 17:54:09 +07:00
|
|
|
import type { LoginResquest, LoginResponse, CreateAccountRequest } from "@/types/auth";
|
2025-12-22 14:53:19 +07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Đăng nhập
|
|
|
|
|
* @param credentials - Thông tin đăng nhập
|
|
|
|
|
* @returns Response chứa token, name, username, access, role
|
|
|
|
|
*/
|
|
|
|
|
export async function login(credentials: LoginResquest): Promise<LoginResponse> {
|
|
|
|
|
const response = await axios.post<LoginResponse>(
|
|
|
|
|
API_ENDPOINTS.AUTH.LOGIN,
|
|
|
|
|
credentials
|
|
|
|
|
);
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 16:46:33 +07:00
|
|
|
/**
|
2026-04-07 13:20:46 +07:00
|
|
|
* Build OAuth login URL by provider
|
|
|
|
|
* @param provider - OAuth provider key (e.g. google, azuread)
|
2026-04-01 16:46:33 +07:00
|
|
|
* @param returnUrl - FE callback url
|
|
|
|
|
*/
|
2026-04-07 13:20:46 +07:00
|
|
|
export function buildOAuthLoginUrl(provider: string, returnUrl: string): string {
|
|
|
|
|
const base = API_ENDPOINTS.AUTH.OAUTH_LOGIN(provider);
|
2026-04-01 16:46:33 +07:00
|
|
|
const encoded = encodeURIComponent(returnUrl);
|
|
|
|
|
return `${base}?returnUrl=${encoded}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-04-07 13:20:46 +07:00
|
|
|
* Build Google OAuth login URL
|
|
|
|
|
* @param returnUrl - FE callback url
|
|
|
|
|
*/
|
|
|
|
|
export function buildGoogleOAuthLoginUrl(returnUrl: string): string {
|
|
|
|
|
return buildOAuthLoginUrl("google", returnUrl);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-04 12:22:15 +07:00
|
|
|
/**
|
|
|
|
|
* Build Microsoft SSO login URL (legacy endpoint)
|
|
|
|
|
* @param returnUrl - FE callback url
|
|
|
|
|
*/
|
|
|
|
|
export function buildMicrosoftSsoLoginUrl(returnUrl: string): string {
|
|
|
|
|
const base = API_ENDPOINTS.AUTH.SSO_LOGIN;
|
|
|
|
|
const encoded = encodeURIComponent(returnUrl);
|
|
|
|
|
return `${base}?returnUrl=${encoded}`;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 13:20:46 +07:00
|
|
|
/**
|
|
|
|
|
* Exchange one-time OAuth code for login payload
|
2026-04-01 16:46:33 +07:00
|
|
|
* @param code - one-time code
|
|
|
|
|
*/
|
2026-04-07 13:20:46 +07:00
|
|
|
export async function exchangeOAuthCode(code: string): Promise<LoginResponse> {
|
|
|
|
|
try {
|
|
|
|
|
const response = await rawAxios.post<LoginResponse>(
|
|
|
|
|
API_ENDPOINTS.AUTH.OAUTH_EXCHANGE,
|
|
|
|
|
{ code }
|
|
|
|
|
);
|
|
|
|
|
return response.data;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (rawAxios.isAxiosError(error)) {
|
|
|
|
|
const status = error.response?.status;
|
|
|
|
|
if (status === 401 || status === 404 || status === 405) {
|
|
|
|
|
const fallbackResponse = await rawAxios.post<LoginResponse>(
|
|
|
|
|
API_ENDPOINTS.AUTH.SSO_EXCHANGE,
|
|
|
|
|
{ code }
|
|
|
|
|
);
|
|
|
|
|
return fallbackResponse.data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Legacy AzureAD SSO URL builder kept for backward compatibility.
|
|
|
|
|
*/
|
|
|
|
|
export function buildSsoLoginUrl(returnUrl: string): string {
|
|
|
|
|
return buildOAuthLoginUrl("azuread", returnUrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Legacy SSO exchange alias kept for backward compatibility.
|
|
|
|
|
*/
|
2026-04-01 16:46:33 +07:00
|
|
|
export async function exchangeSsoCode(code: string): Promise<LoginResponse> {
|
2026-04-07 13:20:46 +07:00
|
|
|
return exchangeOAuthCode(code);
|
2026-04-01 16:46:33 +07:00
|
|
|
}
|
|
|
|
|
|
2026-05-04 12:22:15 +07:00
|
|
|
/**
|
|
|
|
|
* Exchange one-time code by provider without breaking existing flows.
|
|
|
|
|
* - azuread/microsoft: force legacy SSO exchange endpoint
|
|
|
|
|
* - default: use OAuth exchange flow
|
|
|
|
|
*/
|
|
|
|
|
export async function exchangeCodeByProvider(
|
|
|
|
|
code: string,
|
|
|
|
|
provider?: string
|
|
|
|
|
): Promise<LoginResponse> {
|
|
|
|
|
const providerKey = (provider || "").toLowerCase();
|
|
|
|
|
if (providerKey === "microsoft" || providerKey === "azuread") {
|
|
|
|
|
const response = await rawAxios.post<LoginResponse>(
|
|
|
|
|
API_ENDPOINTS.AUTH.SSO_EXCHANGE,
|
|
|
|
|
{ code }
|
|
|
|
|
);
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return exchangeOAuthCode(code);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-22 14:53:19 +07:00
|
|
|
/**
|
|
|
|
|
* Đăng xuất
|
|
|
|
|
*/
|
|
|
|
|
export async function logout(): Promise<void> {
|
|
|
|
|
await axios.delete(API_ENDPOINTS.AUTH.LOGOUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Kiểm tra phiên đăng nhập
|
|
|
|
|
* @param token - Access token
|
|
|
|
|
* @returns Response kiểm tra phiên
|
|
|
|
|
*/
|
|
|
|
|
export async function ping(token?: string): Promise<{ message: string; code: number }> {
|
|
|
|
|
const response = await axios.get(API_ENDPOINTS.AUTH.PING, {
|
|
|
|
|
params: token ? { token } : undefined,
|
|
|
|
|
});
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Lấy CSRF token
|
|
|
|
|
* @returns CSRF token
|
|
|
|
|
*/
|
|
|
|
|
export async function getCsrfToken(): Promise<{ token: string }> {
|
|
|
|
|
const response = await axios.get(API_ENDPOINTS.AUTH.CSRF_TOKEN);
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Thay đổi mật khẩu của user hiện tại
|
|
|
|
|
* @param data - Dữ liệu thay đổi mật khẩu {currentPassword, newPassword}
|
|
|
|
|
*/
|
|
|
|
|
export async function changePassword(data: {
|
|
|
|
|
currentPassword: string;
|
|
|
|
|
newPassword: string;
|
|
|
|
|
}): Promise<{ message: string }> {
|
|
|
|
|
const response = await axios.put(API_ENDPOINTS.AUTH.CHANGE_PASSWORD, data);
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Admin thay đổi mật khẩu của user khác
|
|
|
|
|
* @param data - Dữ liệu {username, newPassword}
|
|
|
|
|
*/
|
|
|
|
|
export async function changePasswordAdmin(data: {
|
|
|
|
|
username: string;
|
|
|
|
|
newPassword: string;
|
|
|
|
|
}): Promise<{ message: string }> {
|
|
|
|
|
const response = await axios.put(
|
|
|
|
|
API_ENDPOINTS.AUTH.CHANGE_PASSWORD_ADMIN,
|
|
|
|
|
data
|
|
|
|
|
);
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tạo tài khoản mới
|
2026-03-06 17:54:09 +07:00
|
|
|
* @param data - Dữ liệu tạo tài khoản (maps to CreateAccountRequest DTO)
|
2025-12-22 14:53:19 +07:00
|
|
|
*/
|
2026-03-06 17:54:09 +07:00
|
|
|
export async function createAccount(data: CreateAccountRequest): Promise<{ message: string }> {
|
2025-12-22 14:53:19 +07:00
|
|
|
const response = await axios.post(API_ENDPOINTS.AUTH.CREATE_ACCOUNT, data);
|
|
|
|
|
return response.data;
|
|
|
|
|
}
|