feat: Passkey (WebAuthn) login (#1111)

* feat(auth): passkey (WebAuthn) login — server endpoints, schema + admin toggle

Add @simplewebauthn/server registration and primary (discoverable) login ceremonies under /api/auth/passkey, a webauthn_credentials + single-use webauthn_challenges schema (migration), the instance-wide passkey_login toggle (default off) enforced before auth by a guard, and require_mfa satisfaction via a verified passkey. RP ID/origin come only from server config (webauthn_rp_id/origins -> APP_URL), never request headers.

* feat(auth): passkey enrolment, login button + admin settings UI

PasskeysSection in account settings (add/rename/remove with a current-password step-up), a 'Sign in with a passkey' button on the login page, the admin enable + RP-ID/origins controls, and a per-user admin reset action.

* i18n(auth): passkey strings across all locales

Add login/settings/admin passkey keys to en and all 19 translated locales.
This commit is contained in:
Maurice
2026-06-05 18:54:13 +02:00
committed by GitHub
parent 247433fb2a
commit a876fb2634
83 changed files with 2421 additions and 8 deletions
@@ -8,6 +8,7 @@ import { authApi, adminApi } from '../../api/client'
import { getApiErrorMessage } from '../../types'
import type { UserWithOidc } from '../../types'
import Section from './Section'
import PasskeysSection from './PasskeysSection'
const MFA_BACKUP_SESSION_KEY = 'trek_mfa_backup_codes_pending'
@@ -395,6 +396,9 @@ export default function AccountTab(): React.ReactElement {
</div>
</div>
{/* Passkeys */}
<PasskeysSection demoMode={demoMode} />
{/* Avatar */}
<div className="flex items-center gap-4">
<div style={{ position: 'relative', flexShrink: 0 }}>