/** * 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('/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('/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 { const refreshToken = getRefreshToken(); if (!refreshToken) { throw new Error('No refresh token available'); } const response = await api.post('/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('/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 { 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 { 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, };