0.2.38: optional two-factor authentication (authenticator-app TOTP)
Per-user opt-in 2FA: enroll from the Two-factor option next to Change password (QR + confirm code + 8 one-time recovery codes), login becomes two-step for enrolled users, disable requires the account password. Escape hatch for lost phones: reset-2fa CLI + Reset Two-Factor StartOS action. Second-factor guesses share the login rate limiter; the pending login window expires after 5 minutes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
053bfeab23
commit
0822eca887
+30
-1
@@ -44,9 +44,15 @@ export interface User {
|
||||
is_active: boolean;
|
||||
is_service_admin: boolean;
|
||||
primary_account_id: number | null;
|
||||
totp_enabled: boolean;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
/** Password was accepted but the account needs its authenticator code to finish signing in. */
|
||||
export interface LoginPending2FA {
|
||||
requires_2fa: true;
|
||||
}
|
||||
|
||||
export interface LinkedAccount {
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -279,11 +285,17 @@ async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
||||
|
||||
export const api = {
|
||||
login: (login: string, password: string) =>
|
||||
request<User>("/api/auth/login", {
|
||||
request<User | LoginPending2FA>("/api/auth/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ login, password }),
|
||||
}),
|
||||
|
||||
verifyTotp: (code: string) =>
|
||||
request<User>("/api/auth/login/verify-totp", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ code }),
|
||||
}),
|
||||
|
||||
logout: () => request<{ status: string }>("/api/auth/logout", { method: "POST" }),
|
||||
|
||||
me: () => request<User>("/api/auth/me"),
|
||||
@@ -294,6 +306,23 @@ export const api = {
|
||||
body: JSON.stringify({ current_password, new_password }),
|
||||
}),
|
||||
|
||||
totpSetup: () =>
|
||||
request<{ secret: string; otpauth_uri: string; qr_svg: string }>("/api/auth/totp/setup", {
|
||||
method: "POST",
|
||||
}),
|
||||
|
||||
totpConfirm: (code: string) =>
|
||||
request<{ recovery_codes: string[] }>("/api/auth/totp/confirm", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ code }),
|
||||
}),
|
||||
|
||||
totpDisable: (password: string) =>
|
||||
request<{ status: string }>("/api/auth/totp/disable", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ password }),
|
||||
}),
|
||||
|
||||
// Entities
|
||||
listEntities: () => request<Entity[]>("/api/entities"),
|
||||
listEntityRollup: () =>
|
||||
|
||||
Reference in New Issue
Block a user