feat(auth): add trusted-device 30-day 2FA skip (frontend)
Adds a "Trust this device for 30 days" checkbox to the 2FA challenge step, and a "Trusted devices" section to the 2FA settings card: list devices with a "this device" badge, per-row revoke, and a confirm-gated "sign out all other trusted devices" action. Both flows are opt-in and additive -- default unchecked, so nothing changes for a user who never uses them.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Alert, Box, Button, TextField, Typography } from "@mui/material";
|
||||
import { Alert, Box, Button, Checkbox, FormControlLabel, TextField, Typography } from "@mui/material";
|
||||
|
||||
import { api, getApiErrorMessage } from "../api";
|
||||
import { useI18n } from "../i18n/I18nProvider";
|
||||
@@ -18,6 +18,7 @@ export default function TwoFactorChallenge({
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
const [code, setCode] = useState("");
|
||||
const [trustDevice, setTrustDevice] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
@@ -25,7 +26,7 @@ export default function TwoFactorChallenge({
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await api.post<ChallengeResponse>("/auth/2fa/challenge", { pendingToken, code });
|
||||
const res = await api.post<ChallengeResponse>("/auth/2fa/challenge", { pendingToken, code, trustDevice });
|
||||
onSuccess(res.data);
|
||||
} catch (e: any) {
|
||||
if (e?.response?.status === 429) {
|
||||
@@ -64,6 +65,11 @@ export default function TwoFactorChallenge({
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={<Checkbox checked={trustDevice} onChange={(e) => setTrustDevice(e.target.checked)} />}
|
||||
label={t("twoFactorTrustDevice")}
|
||||
/>
|
||||
|
||||
<Box sx={{ display: "flex", gap: 1, justifyContent: "flex-end" }}>
|
||||
<Button type="button" variant="text" disabled={loading} onClick={onCancel}>
|
||||
{t("twoFactorBack")}
|
||||
|
||||
Reference in New Issue
Block a user