'use client' import { useState, useEffect } from 'react' import { useAllauthAPI } from '../../contexts/APIContext' import { useStyles } from '../../contexts/StylesContext' import { SettingsSection, SettingsItem, Badge, Button } from './SettingsComponents' import type { Authenticator, TOTPStatus } from '../../types' interface TOTPSetup { secret: string totp_url: string } export function MFASection() { const api = useAllauthAPI() const [authenticators, setAuthenticators] = useState([]) const [loading, setLoading] = useState(true) const [available, setAvailable] = useState(true) const fetchAuthenticators = async () => { try { const res = await api.mfa.list() if (res.status === 200 && res.data) { setAuthenticators(res.data as Authenticator[]) } else { // Non-200 status means MFA not available setAvailable(false) } } catch { setAvailable(false) } setLoading(false) } useEffect(() => { fetchAuthenticators() }, []) if (loading || !available) return null const hasTOTP = authenticators.some(a => a.type === 'totp') return ( {hasTOTP && ( )} ) } // --- TOTP Subsection --- function TOTPSubsection({ hasTOTP, onUpdate }: { hasTOTP: boolean; onUpdate: () => void }) { const api = useAllauthAPI() const styles = useStyles() const [showSetup, setShowSetup] = useState(false) const [setup, setSetup] = useState(null) const [code, setCode] = useState('') const handleStartSetup = async () => { const res = await api.mfa.totp.getStatus() // allauth returns TOTP status with secret and totp_url for setup const data = res.data as TOTPStatus | undefined if (data?.secret && data?.totp_url) { setSetup({ secret: data.secret, totp_url: data.totp_url }) setShowSetup(true) } } const handleActivate = async (e: React.FormEvent) => { e.preventDefault() const res = await api.mfa.totp.activate(code) if (res.status === 200) { setShowSetup(false) setSetup(null) setCode('') onUpdate() } } const handleDeactivate = async () => { if (!confirm('Disable authenticator app?')) return await api.mfa.totp.deactivate() onUpdate() } return ( <>

Authenticator App

{showSetup && setup ? (

Scan this QR code with your authenticator app:

TOTP QR Code

Secret: {setup.secret}

setCode(e.target.value)} placeholder="Verification Code" className={styles.fieldInput} />
) : hasTOTP ? ( Authenticator App Active} actions={} /> ) : ( )} ) } // --- Recovery Codes Subsection --- function RecoveryCodesSubsection() { const api = useAllauthAPI() const styles = useStyles() const [codes, setCodes] = useState([]) const handleView = async () => { const res = await api.mfa.recoveryCodes.list() if (res.status === 200) { setCodes(res.data?.unused_codes || []) } } const handleRegenerate = async () => { if (!confirm('Generate new codes? Old codes will stop working.')) return const res = await api.mfa.recoveryCodes.regenerate() if (res.status === 200) { setCodes(res.data?.unused_codes || []) } } return ( <>

Recovery Codes

{codes.length > 0 ? (
{codes.map((code, i) => {code})}

Store these safely. Each code works once.

) : ( )} ) }