frontend_nyla/src/api/authApi.ts
2026-01-20 00:56:00 +01:00

311 lines
8.1 KiB
TypeScript

import { ApiRequestOptions } from '../hooks/useApi';
import api from '../api';
import { addCSRFTokenToHeaders } from '../utils/csrfUtils';
// ============================================================================
// TYPES & INTERFACES
// ============================================================================
export interface LoginRequest {
username: string;
password: string;
}
export interface LoginResponse {
type: 'local_auth_success';
accessToken?: string;
tokenType?: string;
authenticationAuthority?: string;
label?: any;
fieldLabels?: any;
}
export interface RegisterData {
username: string;
email: string;
fullName: string;
language?: string;
enabled?: boolean;
privilege?: string;
}
export interface RegisterRequest {
userData: {
username: string;
email: string;
fullName: string;
language: string;
enabled: boolean;
privilege: string;
authenticationAuthority: string;
};
frontendUrl: string;
}
export interface PasswordResetRequestResponse {
success: boolean;
message: string;
}
export interface PasswordResetResponse {
success: boolean;
message: string;
}
export interface RegisterResponse {
success: boolean;
message?: string;
user?: {
id: string;
username: string;
email: string;
fullName: string;
language: string;
enabled: boolean;
privilege: string;
};
}
export interface MsalRegisterData {
username: string;
email: string;
fullName: string;
language?: string;
}
export interface UsernameAvailabilityRequest {
username: string;
authenticationAuthority?: string;
}
export interface UsernameAvailabilityResponse {
username: string;
authenticationAuthority: string;
available: boolean;
message: string;
}
// User-Typ wird aus userApi.ts importiert
// Hier nur für Rückwärtskompatibilität
export interface AuthUser {
id: string;
username: string;
email: string;
fullName: string;
language: string;
enabled: boolean;
roleLabels?: string[];
authenticationAuthority: string;
isSysAdmin?: boolean;
[key: string]: any;
}
// Type for the request function passed to API functions
export type ApiRequestFunction = (options: ApiRequestOptions<any>) => Promise<any>;
// ============================================================================
// API REQUEST FUNCTIONS
// ============================================================================
/**
* Login with username and password
* Endpoint: POST /api/local/login
*/
export async function loginApi(loginData: LoginRequest): Promise<LoginResponse> {
// Create the form data in the exact format FastAPI OAuth2 expects
const params = new URLSearchParams();
params.append('username', loginData.username);
params.append('password', loginData.password);
params.append('grant_type', 'password');
params.append('scope', '');
params.append('client_id', '');
params.append('client_secret', '');
// Prepare headers with CSRF token if available
const headers: Record<string, string> = {
'Content-Type': 'application/x-www-form-urlencoded'
};
// Add CSRF token if available (for new security implementation)
addCSRFTokenToHeaders(headers);
// Use the existing api instance with custom headers for this request
const response = await api.post<LoginResponse>('/api/local/login', params, {
headers
});
return response.data;
}
/**
* Fetch current user data
* Endpoint: GET /api/local/me | /api/msft/me | /api/google/me
*/
export async function fetchCurrentUserApi(authAuthority?: string): Promise<AuthUser> {
let endpoint = '/api/local/me';
if (authAuthority === 'msft') {
endpoint = '/api/msft/me';
} else if (authAuthority === 'google') {
endpoint = '/api/google/me';
}
const response = await api.get<AuthUser>(endpoint);
return response.data;
}
/**
* Register a new user (magic link based - no password required)
* Endpoint: POST /api/local/register
*
* After registration, user receives an email with a magic link to set their password.
*/
export async function registerApi(registerData: RegisterData): Promise<RegisterResponse> {
// Prepare data to match backend expectations (no password - magic link flow)
const dataToSend: RegisterRequest = {
userData: {
username: registerData.username,
email: registerData.email,
fullName: registerData.fullName,
language: registerData.language || 'de',
enabled: registerData.enabled !== undefined ? registerData.enabled : true,
privilege: registerData.privilege || 'user',
authenticationAuthority: 'local'
},
frontendUrl: window.location.origin
};
// Prepare headers with CSRF token if available
const headers: Record<string, string> = {
'Content-Type': 'application/json'
};
// Add CSRF token if available (for new security implementation)
addCSRFTokenToHeaders(headers);
const response = await api.post<RegisterResponse>('/api/local/register', dataToSend, {
headers
});
const userData: any = response.data;
return {
success: true,
message: 'Registration successful - check email for password setup link',
user: userData && typeof userData === 'object' && 'id' in userData ? {
id: String(userData.id || ''),
username: String(userData.username || ''),
email: String(userData.email || ''),
fullName: String(userData.fullName || ''),
language: String(userData.language || 'de'),
enabled: Boolean(userData.enabled !== false),
privilege: String(userData.privilege || 'user')
} : undefined
};
}
/**
* Request password reset by username
* Endpoint: POST /api/local/password-reset-request
*
* Sends a reset email to the user's registered email address.
*/
export async function requestPasswordResetApi(username: string): Promise<PasswordResetRequestResponse> {
const headers: Record<string, string> = {
'Content-Type': 'application/json'
};
addCSRFTokenToHeaders(headers);
const response = await api.post<PasswordResetRequestResponse>(
'/api/local/password-reset-request',
{
username,
frontendUrl: window.location.origin
},
{ headers }
);
return response.data;
}
/**
* Reset password using token from magic link
* Endpoint: POST /api/local/password-reset
*/
export async function resetPasswordApi(token: string, password: string): Promise<PasswordResetResponse> {
const headers: Record<string, string> = {
'Content-Type': 'application/json'
};
addCSRFTokenToHeaders(headers);
const response = await api.post<PasswordResetResponse>(
'/api/local/password-reset',
{ token, password },
{ headers }
);
return response.data;
}
/**
* Register with Microsoft account
* Endpoint: POST /api/msft/register
*/
export async function registerWithMsalApi(
request: ApiRequestFunction,
userData: MsalRegisterData
): Promise<RegisterResponse> {
const response = await request({
url: '/api/msft/register',
method: 'post',
data: userData,
additionalConfig: {
headers: {
'Content-Type': 'application/json'
}
}
});
const responseData: any = response;
return {
success: true,
message: 'Registration successful',
user: responseData && typeof responseData === 'object' && 'id' in responseData ? {
id: String(responseData.id || ''),
username: String(responseData.username || ''),
email: String(responseData.email || ''),
fullName: String(responseData.fullName || ''),
language: String(responseData.language || 'en'),
enabled: Boolean((responseData as any).enabled !== false),
privilege: String((responseData as any).privilege || 'user')
} : undefined
};
}
/**
* Check username availability
* Endpoint: GET /api/local/available
*/
export async function checkUsernameAvailabilityApi(
username: string,
authenticationAuthority: string = 'local'
): Promise<UsernameAvailabilityResponse> {
const response = await api.get<UsernameAvailabilityResponse>('/api/local/available', {
params: {
username,
authenticationAuthority
}
});
return response.data;
}
/**
* Logout current user
* Endpoint: POST /api/local/logout
*/
export async function logoutApi(): Promise<void> {
await api.post('/api/local/logout');
}