Skip to content

feat(react): authenticator app enrollment, sign-in and settings screens - #219

Merged
Bccorb merged 9 commits into
mainfrom
feat/totp-react
Oct 27, 2026
Merged

Bccorb merged 9 commits into
mainfrom
feat/totp-react

Conversation

@Bccorb

@Bccorb Bccorb commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Closes #213. Stacked on #218 (shared client pieces); merge that first.

Summary

Authenticator app (TOTP) screens for the React prebuilt UI.

  • Routes: AuthRoutes serves two new screens:
    • /register-authenticator (AuthenticatorRegistration) shows a QR code from qrCode(), the setup key in groups of four with a copy button, and an otpauth:// link for this device. It verifies the first code, shows "Authenticator app added", then continues to /recovery-codes with returnTo, as passkey enrollment does.
    • /authenticator-code (AuthenticatorCodeLogin) signs in with signInWithTotp.
  • Sign-in: the login screen's fallback options always include "Use an authenticator app" once a sign-in has started. /login never lists totp, and the API answers /totp/verify-login for any identifier, so the offer reveals nothing about the account.
  • Recovery sessions and devices without passkeys:
    • PassKeyRegistration always offers "Use an authenticator app" to a recovery session. It is the primary action on a device without passkeys.
    • Outside recovery, it is offered on a device without passkeys only when skipping is allowed. A passkey-only application refuses authenticator sign-in (403 login_method_disabled), so an app set up there could never sign the user in.
    • The enrollment step awaits refreshSession(), so recoverySession is already false when the screen moves on.
  • Step-up:
    • Replacing recovery codes (RecoveryCodeSettings and /recovery-codes) now asks for an authenticator code when the account has one, and falls back to the passkey otherwise.
    • The prompt offers "Use your passkey instead" when the account has passkeys.
    • Cancelling shows no error.
  • Settings: new router-free AuthenticatorAppSettings, exported from the root and rendered by AccountSecurity. It shows status and last use, sets up an app inline, and turns it off with a current code (the API's own proof for /totp/disable).
  • Error copy: comes from totpErrorMessage, which covers:
    • a wrong or reused code (401)
    • lockout with its wait (423)
    • rate limit (429)
    • a passkey-only account (403)
    • a server without the TOTP key (409)
  • Safety: only an otpauth:// URL is rendered as a link or QR code.
  • Re-exports: signInWithTotp, totpErrorMessage, formatTotpSecret, qrCode, TOTP_CODE_LENGTH and QrCode.
  • Copy change: RecoveryCodeSettings now says "You will be asked to confirm it is you first" instead of naming the passkey.

Tests

  • New AuthenticatorViews.test.tsx covers:
    • sign-in success and each error state
    • enrollment: QR, key, copy, link guard, first code and success
    • start failures and retry
  • Extended AccountSecurity, RecoveryViews, RegisterPassKey, login and AuthRoutes for the settings section, the step-up prompt, the recovery-session and unsupported-device offers, and the routes.

Checks

lint, typecheck, format:check, build and test (jest 812 passed, vitest 42 passed) all pass.

Base automatically changed from feat/totp-client to main October 27, 2026 00:29
@Bccorb
Bccorb merged commit dbd4294 into main Oct 27, 2026
5 checks passed
@Bccorb
Bccorb deleted the feat/totp-react branch October 27, 2026 01:53
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.

feat(react): authenticator app (TOTP) enrollment and sign-in screens

1 participant