188 lines
6.4 KiB
TypeScript
188 lines
6.4 KiB
TypeScript
import { LoginDto, RegisterDto, AuthResponse, ApiResponse, UserResponse } from '@goodgo/types';
|
|
|
|
import { apiClient } from './client';
|
|
|
|
/**
|
|
* EN: Authentication API service for frontend
|
|
* VI: Service API xác thực cho frontend
|
|
*/
|
|
export const authApi = {
|
|
/**
|
|
* EN: Register new user account
|
|
* VI: Đăng ký tài khoản người dùng mới
|
|
*/
|
|
register: async (data: RegisterDto): Promise<ApiResponse<AuthResponse>> => {
|
|
return apiClient.post('/auth/register', data);
|
|
},
|
|
|
|
/**
|
|
* EN: Login user and store tokens
|
|
* VI: Đăng nhập người dùng và lưu tokens
|
|
*/
|
|
login: async (data: LoginDto): Promise<ApiResponse<AuthResponse>> => {
|
|
const response = await apiClient.post('/auth/login', data);
|
|
// EN: Store tokens in client and localStorage on successful login
|
|
// VI: Lưu tokens trong client và localStorage khi đăng nhập thành công
|
|
if (response.success && response.data) {
|
|
apiClient.setAuthToken(response.data.accessToken);
|
|
if (typeof window !== 'undefined') {
|
|
localStorage.setItem('refreshToken', response.data.refreshToken);
|
|
}
|
|
}
|
|
return response;
|
|
},
|
|
|
|
/**
|
|
* EN: Logout user and clear tokens
|
|
* VI: Đăng xuất người dùng và xóa tokens
|
|
*/
|
|
logout: async (): Promise<ApiResponse> => {
|
|
// EN: Get refresh token from localStorage for logout request
|
|
// VI: Lấy refresh token từ localStorage cho request logout
|
|
const refreshToken = typeof window !== 'undefined' ? localStorage.getItem('refreshToken') : null;
|
|
const response = await apiClient.post('/auth/logout', { refreshToken });
|
|
// EN: Clear tokens from client and localStorage
|
|
// VI: Xóa tokens khỏi client và localStorage
|
|
apiClient.removeAuthToken();
|
|
if (typeof window !== 'undefined') {
|
|
localStorage.removeItem('refreshToken');
|
|
}
|
|
return response;
|
|
},
|
|
|
|
/**
|
|
* EN: Refresh access token using refresh token
|
|
* VI: Làm mới access token sử dụng refresh token
|
|
*/
|
|
refreshToken: async (refreshToken: string): Promise<ApiResponse<{ accessToken: string }>> => {
|
|
const response = await apiClient.post('/auth/refresh', { refreshToken });
|
|
// EN: Update access token in client on successful refresh
|
|
// VI: Cập nhật access token trong client khi refresh thành công
|
|
if (response.success && response.data) {
|
|
apiClient.setAuthToken(response.data.accessToken);
|
|
}
|
|
return response;
|
|
},
|
|
|
|
/**
|
|
* EN: Get current authenticated user profile
|
|
* VI: Lấy hồ sơ người dùng đã xác thực hiện tại
|
|
*/
|
|
getMe: async (): Promise<ApiResponse<UserResponse>> => {
|
|
return apiClient.get('/identity/profile');
|
|
},
|
|
|
|
/**
|
|
* EN: Change user password
|
|
* VI: Thay đổi mật khẩu người dùng
|
|
*/
|
|
changePassword: async (currentPassword: string, newPassword: string): Promise<ApiResponse> => {
|
|
return apiClient.post('/auth/change-password', { currentPassword, newPassword });
|
|
},
|
|
|
|
/**
|
|
* EN: Request password reset link via email
|
|
* VI: Yêu cầu link đặt lại mật khẩu qua email
|
|
*/
|
|
forgotPassword: async (email: string): Promise<ApiResponse> => {
|
|
return apiClient.post('/auth/forgot-password', { email });
|
|
},
|
|
|
|
/**
|
|
* EN: Reset password using reset token
|
|
* VI: Đặt lại mật khẩu sử dụng reset token
|
|
*/
|
|
resetPassword: async (token: string, newPassword: string): Promise<ApiResponse> => {
|
|
return apiClient.post('/auth/reset-password', { token, newPassword });
|
|
},
|
|
|
|
/**
|
|
* EN: Authenticate with OAuth token from callback
|
|
* VI: Xác thực với OAuth token từ callback
|
|
*/
|
|
oauthLogin: async (accessToken: string): Promise<ApiResponse<AuthResponse>> => {
|
|
// EN: Set the token in the client
|
|
// VI: Đặt token trong client
|
|
apiClient.setAuthToken(accessToken);
|
|
|
|
// EN: Fetch user profile to complete authentication
|
|
// VI: Lấy thông tin user để hoàn tất xác thực
|
|
const userResponse = await apiClient.get('/identity/profile');
|
|
|
|
if (userResponse.success && userResponse.data) {
|
|
// EN: Store refresh token if available (OAuth might not provide refresh token)
|
|
// VI: Lưu refresh token nếu có (OAuth có thể không cung cấp refresh token)
|
|
// Note: For OAuth, we only have access token, refresh token handling depends on backend
|
|
// Ghi chú: Đối với OAuth, chúng ta chỉ có access token, xử lý refresh token phụ thuộc vào backend
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
accessToken,
|
|
refreshToken: '', // EN: OAuth may not provide refresh token / VI: OAuth có thể không cung cấp refresh token
|
|
user: userResponse.data,
|
|
},
|
|
timestamp: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
throw new Error('Failed to fetch user profile / Không thể lấy thông tin người dùng');
|
|
},
|
|
|
|
/**
|
|
* EN: Enable TOTP and get QR code
|
|
* VI: Bật TOTP và lấy mã QR
|
|
*/
|
|
enableTOTP: async (): Promise<ApiResponse<{ secret: string; qrCodeUrl: string }>> => {
|
|
return apiClient.post('/mfa/totp/enable', {});
|
|
},
|
|
|
|
/**
|
|
* EN: Verify and enable TOTP with token
|
|
* VI: Xác thực và bật TOTP với token
|
|
*/
|
|
verifyAndEnableTOTP: async (secret: string, token: string): Promise<ApiResponse> => {
|
|
return apiClient.post('/mfa/totp/verify', { secret, token });
|
|
},
|
|
|
|
/**
|
|
* EN: Disable MFA
|
|
* VI: Tắt MFA
|
|
*/
|
|
disableMFA: async (): Promise<ApiResponse> => {
|
|
return apiClient.post('/mfa/disable', {});
|
|
},
|
|
|
|
/**
|
|
* EN: Get MFA devices
|
|
* VI: Lấy thiết bị MFA
|
|
*/
|
|
getMFADevices: async (): Promise<ApiResponse<Array<{ id: string; type: string; name: string; lastUsedAt: string | null; createdAt: string }>>> => {
|
|
return apiClient.get('/mfa/devices');
|
|
},
|
|
|
|
/**
|
|
* EN: Get user sessions
|
|
* VI: Lấy sessions của người dùng
|
|
*/
|
|
getSessions: async (): Promise<ApiResponse<Array<{ id: string; deviceName: string | null; ipAddress: string | null; lastActivityAt: string | null; createdAt: string; expiresAt: string | null }>>> => {
|
|
return apiClient.get('/sessions');
|
|
},
|
|
|
|
/**
|
|
* EN: Revoke a session
|
|
* VI: Thu hồi một session
|
|
*/
|
|
revokeSession: async (sessionId: string): Promise<ApiResponse> => {
|
|
return apiClient.delete(`/sessions/${sessionId}`);
|
|
},
|
|
|
|
/**
|
|
* EN: Revoke all sessions
|
|
* VI: Thu hồi tất cả sessions
|
|
*/
|
|
revokeAllSessions: async (): Promise<ApiResponse> => {
|
|
return apiClient.delete('/sessions');
|
|
},
|
|
};
|