/** * 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 { const response = await apiClient.post('/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 { 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 { 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 { 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 { const response = await apiClient.post('/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 { 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 { const response = await apiClient.post('/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 { 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 { 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 { const response = await apiClient.get( '/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 { 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 { 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 { const response = await apiClient.get( '/accounts/mfa/webauthn/authenticate/' ); return response.data; } /** * Complete WebAuthn authentication * @param credential The assertion credential from browser */ export async function completeWebAuthnAuthentication( credential: PublicKeyCredential ): Promise { const response = await apiClient.post( '/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, };