UNPKG

codalware-auth

Version:

Complete authentication system with enterprise security, attack protection, team workspaces, waitlist, billing, UI components, 2FA, and account recovery - production-ready in 5 minutes. Enhanced CLI with verification, rollback, and App Router scaffolding.

67 lines (58 loc) 3.07 kB
import { useCallback, useEffect, useState } from 'react'; interface TwoFactorStatus { enabled: boolean; qrCode?: string; secret?: string; backupCodes?: string[]; } export const useTwoFactor = () => { const [status,setStatus] = useState<TwoFactorStatus>({ enabled: false }); const [loading,setLoading] = useState(false); const [error,setError] = useState<string|null>(null); const load = useCallback(async ()=>{ setLoading(true); setError(null); try { const res = await fetch('/api/auth/2fa/setup'); // GET for status if(!res.ok) throw new Error('Failed to load 2FA'); const payload = await res.json(); // API returns { success, data: { enabled, backupCodesCount } } const enabled = payload?.data?.enabled ?? payload.enabled ?? false; setStatus(s => ({ ...s, enabled })); } catch(e: unknown){ setError(e instanceof Error ? e.message : 'Failed to load 2FA'); } finally { setLoading(false); } },[]); const beginSetup = async () => { setLoading(true); setError(null); try { const res = await fetch('/api/auth/2fa/setup', { method: 'POST' }); const payload = await res.json(); if(!res.ok || !payload.success) throw new Error(payload.error?.message || 'Setup failed'); // payload.data: { secret, qrCode, backupCodes } setStatus(prev => ({ ...prev, ...payload.data })); } catch(e: unknown){ setError(e instanceof Error ? e.message : 'Setup failed'); } finally { setLoading(false); } }; const verify = async (token: string) => { setLoading(true); setError(null); try { const res = await fetch('/api/auth/2fa/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token }) }); const payload = await res.json(); if(!res.ok || !payload.success) throw new Error(payload.error?.message || 'Verification failed'); setStatus(s => ({ ...s, enabled: true })); // Refresh session so user object reflects is2FAEnabled try { await fetch('/api/auth/session?update=1'); } catch {} return true; } catch(e: unknown){ setError(e instanceof Error ? e.message : 'Verification failed'); return false; } finally { setLoading(false); } }; const disable = async (token: string) => { setLoading(true); setError(null); try { const res = await fetch('/api/auth/2fa/disable', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token }) }); const payload = await res.json(); if(!res.ok || !payload.success) throw new Error(payload.error?.message || 'Disable failed'); setStatus({ enabled: false }); try { await fetch('/api/auth/session?update=1'); } catch {} return true; } catch(e: unknown){ setError(e instanceof Error ? e.message : 'Disable failed'); return false; } finally { setLoading(false); } }; useEffect(()=>{ load(); },[load]); return { status, loading, error, reload: load, beginSetup, verify, disable }; };