mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 16:11:13 -05:00
211 lines
5.6 KiB
TypeScript
211 lines
5.6 KiB
TypeScript
/**
|
|
* MFA (Multi-Factor Authentication) Service
|
|
*
|
|
* Handles TOTP (Time-based One-Time Password) setup, verification,
|
|
* and management for two-factor authentication.
|
|
*/
|
|
|
|
import { apiClient } from '@/lib/api/client';
|
|
import {
|
|
TOTPSetupResponse,
|
|
TOTPConfirmData,
|
|
TOTPVerifyData,
|
|
MFAChallengeData,
|
|
AuthResponse,
|
|
} from '@/lib/types/auth';
|
|
import { tokenStorage } from './tokenStorage';
|
|
|
|
/**
|
|
* Enable MFA/2FA for current user
|
|
* Returns TOTP secret and QR code URL
|
|
*/
|
|
export async function setupTOTP(): Promise<TOTPSetupResponse> {
|
|
const response = await apiClient.post<TOTPSetupResponse>('/api/v1/auth/mfa/enable');
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Confirm MFA setup with verification token
|
|
* Completes MFA setup after verifying the token is valid
|
|
*/
|
|
export async function confirmTOTP(data: TOTPConfirmData): Promise<void> {
|
|
await apiClient.post('/api/v1/auth/mfa/confirm', data);
|
|
}
|
|
|
|
/**
|
|
* Disable MFA/2FA for current user
|
|
* Removes all TOTP devices and disables MFA requirement
|
|
*/
|
|
export async function disableTOTP(): Promise<void> {
|
|
await apiClient.post('/api/v1/auth/mfa/disable');
|
|
}
|
|
|
|
/**
|
|
* Verify MFA token (for testing)
|
|
* Returns whether the token is valid
|
|
*/
|
|
export async function verifyTOTP(data: TOTPVerifyData): Promise<boolean> {
|
|
try {
|
|
await apiClient.post('/api/v1/auth/mfa/verify', data);
|
|
return true;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Complete MFA challenge during login
|
|
* Called when user has MFA enabled and needs to provide token
|
|
*/
|
|
export async function challengeMFA(data: MFAChallengeData): Promise<AuthResponse> {
|
|
const response = await apiClient.post<AuthResponse>('/api/v1/auth/mfa/challenge', {
|
|
token: data.code,
|
|
});
|
|
|
|
// Store tokens after successful MFA challenge
|
|
tokenStorage.setAccessToken(response.data.access);
|
|
tokenStorage.setRefreshToken(response.data.refresh);
|
|
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Generate new backup codes
|
|
* Returns a list of one-time use backup codes
|
|
*/
|
|
export async function generateBackupCodes(): Promise<string[]> {
|
|
const response = await apiClient.post<{ backup_codes: string[] }>('/api/v1/auth/mfa/backup-codes');
|
|
return response.data.backup_codes;
|
|
}
|
|
|
|
/**
|
|
* Use a backup code to login when TOTP is unavailable
|
|
*/
|
|
export async function useBackupCode(code: string): Promise<AuthResponse> {
|
|
const response = await apiClient.post<AuthResponse>('/api/v1/auth/mfa/backup-code', {
|
|
code,
|
|
});
|
|
|
|
// Store tokens after successful backup code use
|
|
tokenStorage.setAccessToken(response.data.access);
|
|
tokenStorage.setRefreshToken(response.data.refresh);
|
|
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Remove MFA with password confirmation
|
|
*/
|
|
export async function removeMFA(password: string): Promise<void> {
|
|
await apiClient.post('/api/v1/auth/mfa/remove', {
|
|
password,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* WebAuthn/Passkey Support
|
|
* Django-allauth provides WebAuthn through its MFA module
|
|
*/
|
|
|
|
export interface WebAuthnCredential {
|
|
id: string;
|
|
name: string;
|
|
created_at: string;
|
|
last_used?: string;
|
|
}
|
|
|
|
/**
|
|
* Get list of registered WebAuthn credentials (passkeys)
|
|
*/
|
|
export async function getWebAuthnCredentials(): Promise<WebAuthnCredential[]> {
|
|
const response = await apiClient.get<{ credentials: WebAuthnCredential[] }>(
|
|
'/accounts/mfa/webauthn/list/'
|
|
);
|
|
return response.data.credentials;
|
|
}
|
|
|
|
/**
|
|
* Start WebAuthn registration process
|
|
* Returns challenge data for credential creation
|
|
*/
|
|
export async function startWebAuthnRegistration(): Promise<PublicKeyCredentialCreationOptions> {
|
|
const response = await apiClient.get<PublicKeyCredentialCreationOptions>(
|
|
'/accounts/mfa/webauthn/add/'
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Complete WebAuthn registration
|
|
* @param credential The created PublicKeyCredential from browser
|
|
* @param name Optional friendly name for the credential
|
|
*/
|
|
export async function completeWebAuthnRegistration(
|
|
credential: PublicKeyCredential,
|
|
name?: string
|
|
): Promise<void> {
|
|
await apiClient.post('/accounts/mfa/webauthn/add/', {
|
|
credential: JSON.stringify(credential),
|
|
name,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Remove a WebAuthn credential
|
|
* @param credentialId The ID of the credential to remove
|
|
*/
|
|
export async function removeWebAuthnCredential(credentialId: string): Promise<void> {
|
|
await apiClient.post(`/accounts/mfa/webauthn/remove/${credentialId}/`);
|
|
}
|
|
|
|
/**
|
|
* Start WebAuthn authentication challenge
|
|
* Used during login when user has passkey enabled
|
|
*/
|
|
export async function startWebAuthnAuthentication(): Promise<PublicKeyCredentialRequestOptions> {
|
|
const response = await apiClient.get<PublicKeyCredentialRequestOptions>(
|
|
'/accounts/mfa/webauthn/authenticate/'
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Complete WebAuthn authentication
|
|
* @param credential The assertion credential from browser
|
|
*/
|
|
export async function completeWebAuthnAuthentication(
|
|
credential: PublicKeyCredential
|
|
): Promise<AuthResponse> {
|
|
const response = await apiClient.post<AuthResponse>(
|
|
'/accounts/mfa/webauthn/authenticate/',
|
|
{
|
|
credential: JSON.stringify(credential),
|
|
}
|
|
);
|
|
|
|
// Store tokens after successful WebAuthn authentication
|
|
tokenStorage.setAccessToken(response.data.access);
|
|
tokenStorage.setRefreshToken(response.data.refresh);
|
|
|
|
return response.data;
|
|
}
|
|
|
|
// Export all functions as a service object for convenience
|
|
export const mfaService = {
|
|
setupTOTP,
|
|
confirmTOTP,
|
|
disableTOTP,
|
|
verifyTOTP,
|
|
challengeMFA,
|
|
generateBackupCodes,
|
|
useBackupCode,
|
|
removeMFA,
|
|
// WebAuthn/Passkey methods
|
|
getWebAuthnCredentials,
|
|
startWebAuthnRegistration,
|
|
completeWebAuthnRegistration,
|
|
removeWebAuthnCredential,
|
|
startWebAuthnAuthentication,
|
|
completeWebAuthnAuthentication,
|
|
};
|