import { useState } from 'react'; import axios from 'axios'; import { useMsal } from '@azure/msal-react'; import api from '../api'; import { useApiRequest } from './useApi'; // Regular authentication interface LoginResponse { accessToken: string; tokenType: string; label?: any; fieldLabels?: any; } export function useAuth() { const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); const login = async (username: string, password: string): Promise => { setIsLoading(true); setError(null); try { // Create the form data in the exact format FastAPI expects const params = new URLSearchParams(); params.append('username', username); params.append('password', password); params.append('grant_type', 'password'); params.append('scope', ''); params.append('client_id', ''); params.append('client_secret', ''); // Create a custom axios instance for this request const instance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, withCredentials: true, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); const response = await instance.post('/api/token', params); // Store the entire auth response if (response.data.accessToken) { localStorage.setItem('auth_data', JSON.stringify(response.data)); } return response.data; } catch (error: any) { let errorMessage = 'An error occurred during login'; if (error.response) { errorMessage = error.response.data?.detail || 'Invalid username or password'; } else if (error.request) { errorMessage = 'No response received from server'; } else { errorMessage = error.message; } setError(errorMessage); throw error; } finally { setIsLoading(false); } }; return { login, error, isLoading }; } // Microsoft Authentication interface MsalAuthResponse { accessToken: string; tokenType: string; user: { username: string; email: string; fullName: string; mandateId: number; }; } export function useMsalAuth() { const { instance, accounts } = useMsal(); const { request, isLoading, error } = useApiRequest(); const [msalError, setMsalError] = useState(null); const [isMsalLoading, setIsMsalLoading] = useState(false); const loginWithMsal = async (): Promise => { setIsMsalLoading(true); setMsalError(null); try { let msalToken; // If we have an account, try to get the token silently if (accounts.length > 0) { const silentRequest = { scopes: ['user.read'], account: accounts[0] }; try { const response = await instance.acquireTokenSilent(silentRequest); msalToken = response.accessToken; } catch (e) { // If silent token acquisition fails, fall back to popup const response = await instance.acquireTokenPopup(silentRequest); msalToken = response.accessToken; } } else { // No account, do popup login const response = await instance.loginPopup({ scopes: ['user.read'] }); if (response.account) { const tokenResponse = await instance.acquireTokenSilent({ scopes: ['user.read'], account: response.account }); msalToken = tokenResponse.accessToken; } else { throw new Error('Failed to get account after login'); } } // Exchange MSAL token for backend token const response = await api.post('/api/msft/token', null, { headers: { 'Authorization': `Bearer ${msalToken}` } }); // Store the backend token if (response.data.accessToken) { localStorage.setItem('auth_data', JSON.stringify(response.data)); } return response.data; } catch (error: any) { let errorMessage = 'MSAL Login fehlgeschlagen'; if (error.response) { errorMessage = error.response.data?.detail || error.response.data?.message || errorMessage; } else if (error.request) { errorMessage = 'Keine Antwort vom Server erhalten'; } else { errorMessage = error.message || errorMessage; } setMsalError(errorMessage); throw new Error(errorMessage); } finally { setIsMsalLoading(false); } }; return { loginWithMsal, error: msalError || error, isLoading: isMsalLoading || isLoading }; } // Registration interface RegisterData { username: string; password: string; email: string; fullName: string; language?: string; } interface RegisterResponse { success: boolean; message?: string; user?: { username: string; email: string; fullName: string; }; } export function useRegister() { const { request, isLoading, error } = useApiRequest(); const register = async (userData: RegisterData): Promise => { try { // Add default language if not provided const dataToSend = { ...userData, language: userData.language || 'de' }; const response = await request({ url: '/api/users/register', method: 'post', data: dataToSend, additionalConfig: { headers: { 'Content-Type': 'application/json' } } }); return { success: true, message: 'Registration successful', user: response }; } catch (error: any) { throw error; } }; return { register, error, isLoading }; } // Microsoft Registration interface MsalRegisterData { username: string; email: string; fullName: string; language?: string; } export function useMsalRegister() { const { instance, accounts } = useMsal(); const { request, isLoading, error } = useApiRequest(); const registerWithMsal = async (): Promise => { try { if (!accounts || accounts.length === 0) { // If not signed in with Microsoft, sign in first await instance.loginPopup({ scopes: ['user.read'] }); } // Get the current account const currentAccount = instance.getAllAccounts()[0]; if (!currentAccount) { throw new Error('No Microsoft account found'); } // Prepare user data from Microsoft account const userData: MsalRegisterData = { username: currentAccount.username, email: currentAccount.username, fullName: currentAccount.name || currentAccount.username, language: 'de' }; // Register the user through our backend const response = await request({ url: '/api/users/register-with-msal', method: 'post', data: userData, additionalConfig: { headers: { 'Content-Type': 'application/json' } } }); return { success: true, message: 'Registration successful', user: response }; } catch (error: any) { throw error; } }; return { registerWithMsal, error, isLoading }; }