// ================================================================ // frontend/src/api/services/auth.ts // ================================================================ /** * Auth Service - Atomic Registration Architecture * * Backend API structure (3-tier architecture): * - OPERATIONS: auth_operations.py, onboarding_progress.py * * Last Updated: 2025-01-14 * Status: Complete - SetupIntent-first registration flow with 3DS support */ import { apiClient } from '../client'; import { UserRegistration, UserLogin, TokenResponse, RefreshTokenRequest, PasswordChange, PasswordReset, UserResponse, UserUpdate, TokenVerificationResponse, AuthHealthResponse, RegistrationStartResponse, RegistrationCompletionResponse, RegistrationVerification, } from '../types/auth'; export class AuthService { private readonly baseUrl = '/auth'; // User Profile (authenticated) // Backend: services/auth/app/api/users.py // =================================================================== async getProfile(): Promise { // Get current user ID from auth store const { useAuthStore } = await import('../../stores/auth.store'); const user = useAuthStore.getState().user; if (!user?.id) { throw new Error('User not authenticated or user ID not available'); } return apiClient.get(`${this.baseUrl}/users/${user.id}`); } async updateProfile(updateData: UserUpdate): Promise { // Get current user ID from auth store const { useAuthStore } = await import('../../stores/auth.store'); const user = useAuthStore.getState().user; if (!user?.id) { throw new Error('User not authenticated or user ID not available'); } return apiClient.put(`${this.baseUrl}/users/${user.id}`, updateData); } // ATOMIC REGISTRATION: SetupIntent-First Approach // These methods implement the secure registration flow with 3DS support // =================================================================== /** * Start secure registration flow with SetupIntent-first approach * This is the FIRST step in the atomic registration flow * Backend: services/auth/app/api/auth_operations.py:start_registration() */ async startRegistration(userData: UserRegistration): Promise { return apiClient.post(`${this.baseUrl}/start-registration`, userData); } /** * Complete registration after 3DS verification * This is the SECOND step in the atomic registration flow * Backend: services/auth/app/api/auth_operations.py:complete_registration() */ async completeRegistration(verificationData: RegistrationVerification): Promise { return apiClient.post(`${this.baseUrl}/complete-registration`, verificationData); } // =================================================================== // OPERATIONS: Authentication // Backend: services/auth/app/api/auth_operations.py // =================================================================== async login(loginData: UserLogin): Promise { return apiClient.post(`${this.baseUrl}/login`, loginData); } async refreshToken(refreshToken: string): Promise { const refreshData: RefreshTokenRequest = { refresh_token: refreshToken }; return apiClient.post(`${this.baseUrl}/refresh`, refreshData); } async verifyToken(token?: string): Promise { // If token is provided, temporarily set it; otherwise use current token const currentToken = apiClient.getAuthToken(); if (token && token !== currentToken) { apiClient.setAuthToken(token); } const response = await apiClient.post(`${this.baseUrl}/verify`); // Restore original token if we temporarily changed it if (token && token !== currentToken) { apiClient.setAuthToken(currentToken); } return response; } async logout(refreshToken: string): Promise<{ message: string }> { const refreshData: RefreshTokenRequest = { refresh_token: refreshToken }; return apiClient.post<{ message: string }>(`${this.baseUrl}/logout`, refreshData); } async changePassword(passwordData: PasswordChange): Promise<{ message: string }> { return apiClient.post<{ message: string }>(`${this.baseUrl}/change-password`, passwordData); } async requestPasswordReset(email: string): Promise<{ message: string }> { return apiClient.post<{ message: string }>(`${this.baseUrl}/password/reset-request`, { email }); } async resetPasswordWithToken(token: string, newPassword: string): Promise<{ message: string }> { return apiClient.post<{ message: string }>(`${this.baseUrl}/password/reset`, { token, new_password: newPassword }); } // =================================================================== // OPERATIONS: Email Verification // Backend: services/auth/app/api/auth_operations.py // =================================================================== async verifyEmail( userId: string, verificationToken: string ): Promise<{ message: string }> { return apiClient.post<{ message: string }>(`${this.baseUrl}/verify-email`, { user_id: userId, verification_token: verificationToken, }); } // =================================================================== // Account Management (self-service) // Backend: services/auth/app/api/account_deletion.py // =================================================================== async deleteAccount(confirmEmail: string, password: string, reason?: string): Promise<{ message: string; deletion_date: string }> { return apiClient.delete(`${this.baseUrl}/me/account`, { data: { confirm_email: confirmEmail, password: password, reason: reason || '' } }); } async getAccountDeletionInfo(): Promise> { return apiClient.get(`${this.baseUrl}/me/account/deletion-info`); } // =================================================================== // GDPR Consent Management // Backend: services/auth/app/api/consent.py // =================================================================== async recordConsent(consentData: { terms_accepted: boolean; privacy_accepted: boolean; marketing_consent?: boolean; analytics_consent?: boolean; consent_method: string; consent_version?: string; }): Promise> { return apiClient.post(`${this.baseUrl}/me/consent`, consentData); } async getCurrentConsent(): Promise> { return apiClient.get(`${this.baseUrl}/me/consent/current`); } async getConsentHistory(): Promise[]> { return apiClient.get(`${this.baseUrl}/me/consent/history`); } async updateConsent(consentData: { terms_accepted: boolean; privacy_accepted: boolean; marketing_consent?: boolean; analytics_consent?: boolean; consent_method: string; consent_version?: string; }): Promise> { return apiClient.put(`${this.baseUrl}/me/consent`, consentData); } async withdrawConsent(): Promise<{ message: string; withdrawn_count: number }> { return apiClient.post(`${this.baseUrl}/me/consent/withdraw`); } // =================================================================== // Data Export (GDPR) // Backend: services/auth/app/api/data_export.py // =================================================================== async exportMyData(): Promise> { return apiClient.get(`${this.baseUrl}/me/export`); } async getExportSummary(): Promise> { return apiClient.get(`${this.baseUrl}/me/export/summary`); } // =================================================================== // Onboarding Progress // Backend: services/auth/app/api/onboarding_progress.py // =================================================================== async getOnboardingProgress(): Promise> { return apiClient.get(`${this.baseUrl}/me/onboarding/progress`); } async updateOnboardingStep(stepName: string, completed: boolean, data?: Record): Promise> { return apiClient.put(`${this.baseUrl}/me/onboarding/step`, { step_name: stepName, completed: completed, data: data }); } async getNextOnboardingStep(): Promise<{ step: string }> { return apiClient.get(`${this.baseUrl}/me/onboarding/next-step`); } async canAccessOnboardingStep(stepName: string): Promise<{ can_access: boolean }> { return apiClient.get(`${this.baseUrl}/me/onboarding/can-access/${stepName}`); } async completeOnboarding(): Promise<{ success: boolean; message: string }> { return apiClient.post(`${this.baseUrl}/me/onboarding/complete`); } // =================================================================== // Health Check // =================================================================== async healthCheck(): Promise { return apiClient.get(`${this.baseUrl}/health`); } } export const authService = new AuthService();