Skip to content

feat(mfa): opt-in MFA setup UI (TOTP fix + recovery download, passkey enrollment, method hub)#58

Merged
lakhansamani merged 3 commits into
mainfrom
feat/mfa-optin-ui
Jul 12, 2026
Merged

feat(mfa): opt-in MFA setup UI (TOTP fix + recovery download, passkey enrollment, method hub)#58
lakhansamani merged 3 commits into
mainfrom
feat/mfa-optin-ui

Conversation

@lakhansamani

Copy link
Copy Markdown
Contributor

Adds a proper user-facing MFA opt-in experience, modeled on GitHub/Okta security settings. Testable locally in Storybook (npm run storybookMFA/ sidebar) — no server needed.

Components

  • AuthorizerTOTPScanner (reworked) — fixes the alignment issues; numbered steps, bordered/centered QR card, monospace setup key with Copy, a "save these now" warning, and recovery codes with Copy all / Download (.txt) / Print. Accessible (aria-live, labels). Props unchanged; recovery block hides when empty.
  • AuthorizerPasskeyRegister (new) — the missing passkey enrollment (only login existed). Uses the SDK registerPasskey(); optional device name, success/error states, and an info notice when isWebauthnSupported() is false. Optional list of existing passkeys.
  • AuthorizerMFASetup (new) — a hub listing only the available methods (Authenticator/Passkey/Email OTP/SMS OTP), each with "Set up"; TOTP + passkey flow inline, email/SMS delegate via onSetupMethod. Exports AvailableMfaMethods/MfaMethod.
  • Shared MFA icons, copyToClipboard() util, namespaced .mfa-* CSS (no existing rules touched), exports wired.

availableMfaMethods prop → server meta (follow-up)

{ totp?, passkey?, emailOtp?, smsOtp? }  // maps 1:1 to meta.is_totp_mfa_enabled / is_webauthn_enabled / is_email_otp_mfa_enabled / is_sms_otp_mfa_enabled

Omitted/false hides a method, so users only see real options. A companion server PR adds those four booleans to the public meta query.

Verification

tsc --noEmit, npm run build (tsup), npm run build-storybook, prettier — all clean; every state visually verified in Chrome against a live server.

Notes (called out for review)

  • Fixed pre-existing Storybook breakage (a broken addon-styling-webpack, SWC JSX runtime, and global-CSS scoping) so stories build — unrelated to the feature but required to run them.
  • Surfaced a latent MessageType.Info contrast bug (white text on light bg); worked around at call sites via extraStyles, worth fixing at the Message source separately.
  • Interactive passkey success/error need a live server (WebAuthn ceremony can't be mocked); rendered states are deterministic.
  • eslint.config.js has a pre-existing flat-config bug (root: true) that breaks npm run lint — left untouched (out of scope).

- new AuthorizerMFASetup hub lists server-supported methods (TOTP,
  passkey, email/SMS OTP) via availableMfaMethods prop, mapping to the
  upcoming public meta fields
- new AuthorizerPasskeyRegister enrols passkeys via SDK registerPasskey,
  guarding unsupported browsers
- rework AuthorizerTOTPScanner: aligned QR/secret layout, copy setup
  key, recovery codes with copy/download/print + save-now warning
- Storybook stories cover each method/state; fix preview build (drop
  broken addon-styling-webpack, automatic JSX runtime, global default.css)
Stray pnpm-lock.yaml (stale since Apr, npm is actual pm per main.yml)
made size-limit-action fall back to pnpm, which isn't installed on
the runner. Drop the dead lockfile and bump checkout/action versions.
actions/checkout@v1 is six years stale; pin size-limit-action to
v1.8.0 instead of the floating v1 tag and add setup-node so the
action's npm install has a consistent Node version.
@github-actions

Copy link
Copy Markdown

size-limit report 📦

Path Size
dist/index.cjs 55.36 KB (+4.12% 🔺)
dist/index.mjs 54.94 KB (+3.93% 🔺)

@lakhansamani lakhansamani merged commit 0f9792c into main Jul 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant