Security
Sessions and security for an AI product. Active devices with sign-out that animates rows away, a password change with a live strength meter, two-factor setup with a real QR code, a 6-digit check and downloadable recovery codes, passkeys through WebAuthn, and account deletion behind a typed confirmation.
Every AI product ends up with the same security page: where you’re signed in, how you sign in, and how to leave. Security is that page, built on the Settings block’s groups and rows, with every flow wired to async callbacks you own.
Active sessions lists each device with its browser, system, location and when it was last active, in plain relative time. This device is marked and can’t be signed out from here. Signing out of one device shows progress in its button, then the row folds away and focus moves to the next row. Signing out everywhere else asks first and names the devices it will sign out.
Change password checks as you type: a four-step strength meter and a checklist of what’s still missing, without blocking anything you type. If your server says the current password is wrong, the message shows under that field and focus goes back to it, with everything you typed kept. You can sign out other sessions in the same step.
Two-factor setup draws a real, scannable QR code for the otpauth link your server returns, shows the setup key with a copy button for when scanning isn’t possible, and on a phone offers to open the link in an authenticator app. The 6-digit code checks itself as soon as it’s complete, shakes and clears on a wrong code, then shows recovery codes to copy or download as a text file. Turning it off asks first.
Passkeys calls your WebAuthn flow and handles the browser’s answers: closing the prompt adds nothing and shows no error, and a device that already has a passkey says so. Deleting the account needs the exact phrase, lists what goes with it, and keeps the dialog open with your message if the server says no.
Add the Pro registry to components.json
components.json Add your token
Create a token on your account page and put it in
.env.localasHEXTAUI_PRO_TOKEN.Add the block
pnpm dlx shadcn@latest add @hextaui-pro/security
Wire it to your API
Pass what the account has now and an async callback for each action. Resolve when the server is done and refresh the data, and each part shows its own progress. Throw to show your error message in place, and the person’s input stays.
Use the parts on their own
SecuritySessions, SecurityPasswordRow, SecurityTwoFactorRow, SecurityPasskeys and SecurityDeleteAccount each work alone, so you can put them in any section. Return field errors from onChangePassword to show them under the field.
Anatomy
The parts you compose, from the outside in.
| Part | Description |
|---|---|
SecuritySettings | Everything below in one call. Each part appears when you pass the data and callbacks it needs. |
SecuritySessions | A group listing signed-in devices, with sign out per device and for all other sessions. |
SecurityPasswordRow | A row that opens the change password dialog. |
SecurityTwoFactorRow | A row with the two-factor status, the setup dialog and the turn-off confirmation. |
SecurityPasskeys | A group listing passkeys, with add and remove. |
SecurityDeleteAccount | A group with the delete account row and its typed confirmation. |
measurePassword | The strength check the password dialog uses, for your own forms. |
| Prop | Type | Default |
|---|---|---|
emailThe account’s email. Used in the delete phrase, the password manager hint and the recovery codes file. | string | – |
sessions{ id, browser, os, device?, location?, lastActive, current? }. device is "desktop", "laptop", "phone" or "tablet". | SecuritySession[] | – |
onSignOutSessionSign out one session. Remove it from sessions when it resolves and the row folds away. | (id: string) => Promise<void> | – |
onSignOutOtherSessionsSign out every session except the current one. Runs after the person confirms. | () => Promise<void> | – |
passwordChangedAtShown as Last changed under Password. | Date | string | number | null | – |
onChangePasswordReturn { currentPassword } or { newPassword } to show a message under that field, or throw to show it above the buttons. | ({ currentPassword, newPassword, signOutOthers }) => Promise<void | errors> | – |
twoFactorEnabledWhether two-factor is on. | boolean | false |
onStartTwoFactorCreate a pending secret when the setup dialog opens. uri is the otpauth link drawn as the QR code; secret defaults to the one in uri. | () => Promise<{ uri, secret?, recoveryCodes? }> | – |
onVerifyTwoFactorCheck the 6-digit code and turn two-factor on. Return recovery codes to show them, or throw if the code is wrong. | (code: string) => Promise<void | string[]> | – |
onDisableTwoFactorTurn two-factor off. Runs after the person confirms. | () => Promise<void> | – |
passkeys{ id, name, createdAt, lastUsed? }. | SecurityPasskey[] | – |
onAddPasskeyRun your WebAuthn registration. A NotAllowedError or AbortError counts as cancelled and shows nothing. | () => Promise<void> | – |
onRemovePasskeyRemove a passkey. Runs after the person confirms. | (id: string) => Promise<void> | – |
passkeysSupportedOverride the check for WebAuthn support. | boolean | detected |
onDeleteAccountDelete the account. Runs after the person types the phrase. Throw to keep the dialog open with your message. | () => Promise<void> | – |
deleteConsequencesWhat gets deleted, listed in the confirmation. | ReactNode[] | – |
SecuritySessions
Also accepts every SettingsGroup prop.
| Prop | Type | Default |
|---|---|---|
sessionsThe signed-in devices. | SecuritySession[] | – |
onSignOutSign out one session. | (id: string) => Promise<void> | – |
onSignOutOthersSign out every other session. | () => Promise<void> | – |
titleThe group heading. | ReactNode | "Active sessions" |
| Prop | Type | Default |
|---|---|---|
emailFilled into a hidden username field so password managers update the right login. | string | – |
changedAtWhen the password last changed. | Date | string | number | null | – |
onChangePasswordSame as on SecuritySettings. | (change) => Promise<void | errors> | – |
| Prop | Type | Default |
|---|---|---|
emailNamed in the confirmation and the recovery codes file. | string | – |
enabledWhether two-factor is on. | boolean | – |
onStartSame as onStartTwoFactor. | () => Promise<{ uri, secret?, recoveryCodes? }> | – |
onVerifySame as onVerifyTwoFactor. | (code: string) => Promise<void | string[]> | – |
onDisableSame as onDisableTwoFactor. | () => Promise<void> | – |
SecurityPasskeys
Also accepts every SettingsGroup prop.
| Prop | Type | Default |
|---|---|---|
passkeysThe saved passkeys. | SecurityPasskey[] | – |
onAddRun your WebAuthn registration. | () => Promise<void> | – |
onRemoveRemove a passkey. | (id: string) => Promise<void> | – |
supportedWhether this browser can create passkeys. | boolean | detected |
SecurityDeleteAccount
Also accepts every SettingsGroup prop.
| Prop | Type | Default |
|---|---|---|
emailThe confirmation phrase is delete followed by this. | string | – |
onDeleteDelete the account. | () => Promise<void> | – |
consequencesWhat gets deleted with it. | ReactNode[] | – |
titleThe group heading. | ReactNode | "Danger zone" |
| Key | Action |
|---|---|
| Tab | Moves through the rows and their buttons, then through each dialog. |
| Enter | Submits the password form from any field, and deletes the account from the phrase field once it matches. |
| Escape | Closes a dialog, except while something is saving. |
| 0–9 | Fills the verification code. It checks itself once all six digits are in, and pasting a code works too. |
- Destructive actions never get focus first. Confirmations name what they affect, like the devices being signed out or the email being deleted, and the delete phrase field gets focus instead of the button.
- When a row folds away, focus moves to the next row’s button, or the previous one, so it never drops to the page. Closing a dialog returns focus to the button that opened it, or to its replacement when that button is gone.
- Sign-outs, added and removed passkeys and the password strength are announced politely. Errors from your callbacks are announced as alerts and stay next to the field or button they belong to.
- Each password requirement says whether it’s met, the QR code has a text label, and the setup key and recovery codes are readable text you can select.
- With reduced motion, rows fade instead of folding and step changes don’t slide. In high contrast mode the QR code and strength meter keep their shapes.
Code
12 files, added to components/blocks/security.