Files
Novault-Frontend-web/src/services/authService.ts

206 lines
4.7 KiB
TypeScript

/**
* Authentication Service - Handles user authentication operations
* Feature: api-interface-optimization
* Validates: Requirements 12, 13
*/
import api from './api';
// Token storage keys
const ACCESS_TOKEN_KEY = 'access_token';
const REFRESH_TOKEN_KEY = 'refresh_token';
// Types
export interface User {
id: number;
email: string;
username: string;
avatar?: string;
is_active: boolean;
created_at: string;
updated_at: string;
}
export interface TokenPair {
access_token: string;
refresh_token: string;
expires_in: number;
}
export interface RegisterInput {
email: string;
password: string;
username: string;
}
export interface LoginInput {
email: string;
password: string;
}
export interface AuthResponse {
success: boolean;
data: {
user: User;
tokens: TokenPair;
};
}
export interface RefreshResponse {
success: boolean;
data: TokenPair;
}
// Token management
export function getAccessToken(): string | null {
return localStorage.getItem(ACCESS_TOKEN_KEY);
}
export function getRefreshToken(): string | null {
return localStorage.getItem(REFRESH_TOKEN_KEY);
}
export function setTokens(tokens: TokenPair): void {
localStorage.setItem(ACCESS_TOKEN_KEY, tokens.access_token);
localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refresh_token);
}
export function clearTokens(): void {
localStorage.removeItem(ACCESS_TOKEN_KEY);
localStorage.removeItem(REFRESH_TOKEN_KEY);
}
export function isAuthenticated(): boolean {
return !!getAccessToken();
}
/**
* Register a new user
* Validates: Requirements 12.1, 12.2
*/
export async function register(input: RegisterInput): Promise<{ user: User; tokens: TokenPair }> {
const response = await api.post<AuthResponse>('/auth/register', input);
if (response.success && response.data) {
setTokens(response.data.tokens);
return response.data;
}
throw new Error('Registration failed');
}
/**
* Login with email and password
* Validates: Requirements 12.2
*/
export async function login(input: LoginInput): Promise<{ user: User; tokens: TokenPair }> {
const response = await api.post<AuthResponse>('/auth/login', input);
if (response.success && response.data) {
setTokens(response.data.tokens);
return response.data;
}
throw new Error('Login failed');
}
/**
* Refresh access token using refresh token
* Validates: Requirements 12.4
*/
export async function refreshAccessToken(): Promise<TokenPair> {
const refreshToken = getRefreshToken();
if (!refreshToken) {
throw new Error('No refresh token available');
}
const response = await api.post<RefreshResponse>('/auth/refresh', {
refresh_token: refreshToken,
});
if (response.success && response.data) {
setTokens(response.data);
return response.data;
}
throw new Error('Token refresh failed');
}
/**
* Logout - clear tokens
*/
export function logout(): void {
clearTokens();
}
/**
* Get GitHub OAuth login URL
* Validates: Requirements 13.1
*/
export function getGitHubLoginUrl(state?: string): string {
const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:2612/api/v1';
const url = new URL(`${baseUrl}/auth/github`);
if (state) {
url.searchParams.append('state', state);
}
return url.toString();
}
/**
* Redirect to GitHub OAuth login
* Validates: Requirements 13.1
*/
export function loginWithGitHub(state?: string): void {
window.location.href = getGitHubLoginUrl(state);
}
/**
* Handle GitHub OAuth callback
* Validates: Requirements 13.4, 13.5
*/
export async function handleGitHubCallback(code: string): Promise<{ user: User; tokens: TokenPair }> {
const response = await api.get<AuthResponse>('/auth/github/callback', { code });
if (response.success && response.data) {
setTokens(response.data.tokens);
return response.data;
}
throw new Error('GitHub authentication failed');
}
/**
* Get current user information
*/
export async function getCurrentUser(): Promise<User> {
const response = await api.get<{ success: boolean; data: User }>('/auth/me');
if (response.success && response.data) {
return response.data;
}
throw new Error('Failed to get user information');
}
/**
* Update user password
*/
export async function updatePassword(oldPassword: string, newPassword: string): Promise<void> {
const response = await api.post<{ success: boolean }>('/auth/password', {
old_password: oldPassword,
new_password: newPassword,
});
if (!response.success) {
throw new Error('Failed to update password');
}
}
export default {
register,
login,
logout,
refreshAccessToken,
getAccessToken,
getRefreshToken,
setTokens,
clearTokens,
isAuthenticated,
loginWithGitHub,
getGitHubLoginUrl,
handleGitHubCallback,
getCurrentUser,
updatePassword,
};