ProfileForm, PasswordForm, EmailChangeForm, SessionsList, and TOTPSetup — all designed to be dropped into any authenticated page because they source their own state via hooks internally.
Each component is intentionally self-contained. You do not need to fetch user data before rendering them, pass user objects as props, or manage loading state. The components use useUser, useSessions, and useAilita internally and handle all async operations, error display, and state transitions themselves.
ProfileForm
Renders first name, last name, and phone fields; the email field is read-only (changing it requiresEmailChangeForm). Internally uses useUser() to pre-populate fields on mount and to call PATCH /users/me on submit.
Props
Optional callback fired after a successful profile update. The form handles its own loading and error state via
useUser internally — you do not need to pass isLoading or error as props.Usage
The form pre-populates from
useUser().user on mount and resets if the user object changes externally (for example, if the user data is refreshed after an admin update). The Save button is disabled until the user makes a change (isDirty guard) — submitting an unchanged form is not possible.Validation rules
The form validates on submit using Zod:firstName— required, min 1 characterlastName— required, min 1 characterphone— optional; any string value is accepted, including an empty string to clear the field
error state from useUser (API-level errors) is rendered below all fields.
PasswordForm
Allows the authenticated user to change their password; requires the current password plus a new password that satisfies the strength requirements.Props
Optional callback fired after the password is changed successfully. The form resets to its empty state before firing this callback.
Usage
If the user has 2FA enabled (
user.totpEnabled === true), a TOTP code field appears automatically. The schema validation requires a 6-digit numeric code in that case. You do not need to pass any prop to control this — it is driven by user state read from useUser() internally.Validation rules
The password schema is built dynamically based onuser.totpEnabled:
currentPassword— required, min 1 characternewPassword— min 8 characters, must contain at least one letter and one numbertotpCode— required only whenuser.totpEnabled === true; must be exactly 6 numeric digits
onSuccess callback fires at this point.
EmailChangeForm
Initiates an email-change flow by sending a verification code to the new address, then completing it via an internally renderedChallengeView component.
Props
Optional callback fired after the new email is confirmed and the change is committed. This fires only after the OTP verification step (step 2), not after the initial form submission (step 1).
Usage
This component is two-step internally. Step 1: the user submits the new email address, which calls
POST /users/me/email-change and returns a challengeId. Step 2: the component renders ChallengeView with type="EMAIL" using that challengeId. The onSuccess callback fires only after step 2 (code verification) completes successfully and the challenge returns status: "COMPLETED".Internal state transitions
onSuccess fires, the component renders a green confirmation message in place of the form. There is no way to reset the component to the initial state from the outside — if you need to allow another email change, unmount and remount it.
SessionsList
Displays the user’s active sessions with device details (browser, OS, IP, last activity) and provides per-session revoke controls and a revoke-all button.Props
This component accepts no props. It is fully self-contained: it fetches sessions on mount viauseSessions() and manages all revoke state internally. You cannot pass custom render logic, session data, or callbacks.
This component provides the same UI as the
SessionsList built in the useSessions usage example in session-management.mdx. Use SessionsList when you want the default device-card UI. Use the useSessions hook directly when you need custom rendering, additional metadata, or integration with your own design system.Usage
Loading and error states
While sessions are loading on mount, the component renders a centered spinner. If the fetch fails, an error message is displayed inline. Revoke operations disable the individual revoke button with a loading indicator while the request is in flight.TOTPSetup
A multi-step component guiding the user through TOTP 2FA setup or removal, including QR code display, backup code generation, and confirmation via a 6-digit code.Props
Optional callback fired after 2FA is successfully enabled — specifically after
verifyTotp(code) succeeds and totpEnabled is set to true on the user. This callback is not fired when the user disables 2FA.The disable-2FA button is only shown if the merchant permits it (
merchant.allowUserDisableTotp !== false). If the merchant has locked 2FA as mandatory, the user sees “Disabling 2FA is not permitted on this platform” and cannot remove it regardless of their current 2FA status.Setup flow
Initiate setup
The component calls
initTotp(), which hits POST /users/me/totp/init and returns a qrUri and a list of backupCodes. The QR code is rendered as an image using an external QR service, and backup codes are displayed in a copyable grid.Scan and save backup codes
The user scans the QR code with their authenticator app (Google Authenticator, Authy, 1Password, etc.) and saves the backup codes in a secure location. The user then clicks the “I scanned the QR” button to advance to confirmation.
Disable flow
Whenuser.totpEnabled === true and merchant.allowUserDisableTotp !== false, a “Disable 2FA” link is shown. Clicking it transitions to a confirmation step that requires the user to enter a valid TOTP code before removeTotp(code) is called. This prevents accidental or unauthorized 2FA removal.
Usage
Next steps
Admin Module
UsersTable, UserDetail, MerchantSettings, and RolesManager prop reference.
Challenge Module
ChallengeView props, dual-response contract, and expiry handling.

