admin / Apex
publicBid Management and Orchestration Tool with AI Capability
Apex / Synapse-Apexv2 / frontend / src / pages / MfaEnroll.tsx
1994 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import { useEffect, useState } from "react"; import { api } from "../lib/api"; import { useAuth } from "../lib/auth"; export default function MfaEnroll({ optional = false }: { optional?: boolean }) { const { refresh } = useAuth(); const [data, setData] = useState<any>(null); const [otp, setOtp] = useState(""); const [err, setErr] = useState(""); async function start() { setErr(""); setData(await api.post("/auth/mfa/enroll")); } useEffect(() => { if (!optional) start(); }, []); async function verify(e: React.FormEvent) { e.preventDefault(); setErr(""); try { await api.post("/auth/mfa/verify", { otp }); await refresh(); } catch (e: any) { setErr(e.message); } } return ( <div className="login-wrap"> <div className="card login-card" style={{ width: 420 }}> <h1>Set up multi-factor authentication</h1> <p className="muted"> {optional ? "Add an authenticator app for extra security." : "Your administrator requires MFA. Scan the QR code with an authenticator app, then enter a code to confirm."} </p> {!data && optional && <button onClick={start}>Begin enrolment</button>} {data && ( <> <div dangerouslySetInnerHTML={{ __html: data.qr_svg }} style={{ maxWidth: 200 }} /> <p className="muted" style={{ fontSize: 12 }}>Secret: {data.secret}</p> <p style={{ fontSize: 12 }}> Recovery codes (store safely): <br /> <code>{data.recovery_codes.join(" ")}</code> </p> <form onSubmit={verify}> <label>Enter a 6-digit code to confirm</label> <input value={otp} onChange={(e) => setOtp(e.target.value)} autoFocus /> {err && <div className="err">{err}</div>} <button style={{ marginTop: 12 }}>Confirm</button> </form> </> )} </div> </div> ); } |