Headless / Account
Two-factor authentication
An authenticator app for the signed-in account: setting one up, the recovery codes, replacing or removing it, and the second-factor step of signing in. A subpath of its own, installed only where an app offers it. It exports SignIn and User as the auth namespaces with its parts added, so a screen writes SignIn.TwoFactorCode and User.TwoFactor.Root, importing both from here.
38 public parts · 3examples
@slices.sh/auth/headless/two-factorView as Markdown ↗Your design. Our behavior.
Explore the tree to see what each part controls. Gates reveal the relevant state; roots outline their scope.
User.Root · Scope
Installation
Choose what your component needs. Run these commands in an initialized Next.js app.
Before you start
The steps below run in a Next.js app with shadcn set up (it has a components.json). In an existing Next.js app, such as one from create-next-app, set shadcn up first:
npx shadcn@latest init -t next -b base -p novaOr start fresh: the slices CLI creates the app and sets it up.
npx slices.sh installInstall the service registry
Adds services/index.ts, which import "@/services" loads. A provider setup writes the same file, so skip this if your app has one.
npx add servicesInstall the headless library
npmAdd the React parts to your app, then compose them with your own elements.
npm install @slices.sh/auth@^0.1.10Import from @slices.sh/auth/headless/two-factor.
Install the service
Connect the parts to a provider. Skip this step if this service is already configured in your app.
npx add auth.betterauth --two-factorAdds service configuration and API routes to your app, with the provider dependencies. For a headless composition, add import "@/services" after "use client".
The slices CLI installs the service and provisions its required resources in one command.
Set BETTER_AUTH_URL to your app origin. Memory is for local development; use a persistent database for deployment. Neon and Supabase also require the migration script printed by the installer.
Provider setup notes
- BETTER_AUTH_SECRET signs every session and is generated into .env.local while this installs (32 random bytes, base64, nothing leaves the machine). Changing it signs everyone out; in production set the same one on every instance.
- The public origin (OAuth callbacks, the passkey domain) is the one each request comes to in development, and the deployment's own on Vercel. Elsewhere, or behind a proxy or a custom domain, set BETTER_AUTH_URL, such as https://acme.com.
Start small
Parts bring the behavior. Use their default elements, or supply your own with render.
"use client"import "@/services"import { User } from "@slices.sh/auth/headless/two-factor"export function Example() { return ( <User.Root> <User.TwoFactor.Root> <User.TwoFactor.Step name="off"> <User.TwoFactor.Begin>Enable two-factor</User.TwoFactor.Begin> </User.TwoFactor.Step> <User.TwoFactor.Step name="confirm"> <User.TwoFactor.Form> <User.TwoFactor.Password aria-label="Current password" /> <User.TwoFactor.Confirm>Continue</User.TwoFactor.Confirm> </User.TwoFactor.Form> </User.TwoFactor.Step> <User.TwoFactor.Step name="scan"> <User.TwoFactor.Form> <User.TwoFactor.Qr /> <User.TwoFactor.Secret /> <User.TwoFactor.Code aria-label="Authenticator code" /> <User.TwoFactor.Enable>Verify</User.TwoFactor.Enable> </User.TwoFactor.Form> </User.TwoFactor.Step> <User.TwoFactor.Step name="verified"> <User.TwoFactor.ShowCodes> Save recovery codes </User.TwoFactor.ShowCodes> </User.TwoFactor.Step> <User.TwoFactor.Step name="codes"> <User.TwoFactor.BackupCode /> <User.TwoFactor.CopyCodes>Copy codes</User.TwoFactor.CopyCodes> <label> <User.TwoFactor.CodesStored />I saved these codes </label> <User.TwoFactor.Finish>Done</User.TwoFactor.Finish> </User.TwoFactor.Step> <User.TwoFactor.Step name="on"> Your account is protected. </User.TwoFactor.Step> <User.TwoFactor.Error /> </User.TwoFactor.Root> </User.Root> )}Enable password and two-factor. This wizard assumes the signed-in account already has a password.
API reference
Every public part used by this experience is listed below. Gates render children without adding an element. Element parts accept native element props and render; function children receive the state declared in their props. Scopes provide context rather than a visual element.
User.TwoFactor.Dialogcontent
Step takes name, one step or a list. Status gates on name="off" | "on" | "unavailable" whatever step the wizard is in, for the summary beside the buttons. Dialog maps the wizard's open state onto a host dialog through render={<Dialog />}; once the code is verified it cannot be dismissed until the recovery codes are acknowledged. Available is a gate for a settings entry that should exist only where two-factor does.
Required scope
User.TwoFactor.Dialog requires User.TwoFactor.Root.
Props
2 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/dialog.tsx
User.TwoFactor.Statusgate
Step takes name, one step or a list. Status gates on name="off" | "on" | "unavailable" whatever step the wizard is in, for the summary beside the buttons. Dialog maps the wizard's open state onto a host dialog through render={<Dialog />}; once the code is verified it cannot be dismissed until the recovery codes are acknowledged. Available is a gate for a settings entry that should exist only where two-factor does.
Props
2 documented props
| Prop | Type | Default |
|---|---|---|
nameRequired | "off" | "on" | "unavailable" | — |
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/status.tsx
User.TwoFactor.Availablegate
Step takes name, one step or a list. Status gates on name="off" | "on" | "unavailable" whatever step the wizard is in, for the summary beside the buttons. Dialog maps the wizard's open state onto a host dialog through render={<Dialog />}; once the code is verified it cannot be dismissed until the recovery codes are acknowledged. Available is a gate for a settings entry that should exist only where two-factor does.
Props
1 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/available.tsx
User.TwoFactor.Rootscope
The wizard around the steps: the fields it collects, and how far it has got. They live here rather than in a form because setting an authenticator up spans several screens — confirm the password, scan the code, put the recovery codes away — and each one is a gate that mounts and unmounts.
Props
3 documented props
| Prop | Type | Default |
|---|---|---|
configThe auth config, a slug from the registry ( | string | — |
enabledLeft out or | Enabled | — |
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/root.tsx
User.TwoFactor.Stepgate
Step takes name, one step or a list. Status gates on name="off" | "on" | "unavailable" whatever step the wizard is in, for the summary beside the buttons. Dialog maps the wizard's open state onto a host dialog through render={<Dialog />}; once the code is verified it cannot be dismissed until the recovery codes are acknowledged. Available is a gate for a settings entry that should exist only where two-factor does.
Props
3 documented props
| Prop | Type | Default |
|---|---|---|
nameRequired | TwoFactorStep | readonly TwoFactorStep[] | — |
childrenContent rendered inside this part. | ReactNode | — |
render | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/step.tsx
User.TwoFactor.Formaction · <form>
Form holds the fields and prevents the page submit; inside a Root it uses the wizard's fields. Label takes field="account" | "password" | "new-password" | "code" | "codes-stored". Account is a read-only username input, so a password manager knows whose password this is. Password is the current password. Begin asks for setup and moves to confirm; Confirm submits the password for whatever was asked; Cancel leaves the wizard and forgets the secret shown; UseAnotherAccount signs out from the confirm step. Start runs setup straight from a password, without the wizard.
Props
2 documented props · Native <form> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/form.tsx
User.TwoFactor.Disabledgate
Disabled, Setup and Enabled read the person and the setup, so they work outside a Root: off with no setup, off with a setup in progress, on.
Props
1 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/disabled.tsx
User.TwoFactor.Setupgate
Disabled, Setup and Enabled read the person and the setup, so they work outside a Root: off with no setup, off with a setup in progress, on.
Props
1 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/setup.tsx
User.TwoFactor.Enabledgate
Disabled, Setup and Enabled read the person and the setup, so they work outside a Root: off with no setup, off with a setup in progress, on.
Props
1 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/enabled.tsx
User.TwoFactor.Labelcontent · <label>
Form holds the fields and prevents the page submit; inside a Root it uses the wizard's fields. Label takes field="account" | "password" | "new-password" | "code" | "codes-stored". Account is a read-only username input, so a password manager knows whose password this is. Password is the current password. Begin asks for setup and moves to confirm; Confirm submits the password for whatever was asked; Cancel leaves the wizard and forgets the secret shown; UseAnotherAccount signs out from the confirm step. Start runs setup straight from a password, without the wizard.
Required scope
User.TwoFactor.Label field=
Props
3 documented props · Native <label> attributes supported
| Prop | Type | Default |
|---|---|---|
fieldRequired | TwoFactorField | — |
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/label.tsx
User.TwoFactor.Passwordinput · <input>
Form holds the fields and prevents the page submit; inside a Root it uses the wizard's fields. Label takes field="account" | "password" | "new-password" | "code" | "codes-stored". Account is a read-only username input, so a password manager knows whose password this is. Password is the current password. Begin asks for setup and moves to confirm; Confirm submits the password for whatever was asked; Cancel leaves the wizard and forgets the secret shown; UseAnotherAccount signs out from the confirm step. Start runs setup straight from a password, without the wizard.
Required scope
User.TwoFactor.Password must be inside <User.TwoFactor.Form>.
Props
2 documented props · Native <input> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { invalid: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/password.tsx
User.TwoFactor.Startaction · <button>
Form holds the fields and prevents the page submit; inside a Root it uses the wizard's fields. Label takes field="account" | "password" | "new-password" | "code" | "codes-stored". Account is a read-only username input, so a password manager knows whose password this is. Password is the current password. Begin asks for setup and moves to confirm; Confirm submits the password for whatever was asked; Cancel leaves the wizard and forgets the secret shown; UseAnotherAccount signs out from the confirm step. Start runs setup straight from a password, without the wizard.
Required scope
User.TwoFactor.Start must be inside <User.TwoFactor.Form>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/start.tsx
User.TwoFactor.Qrcontent · <svg>
Qr is an <svg> drawn locally as one currentColor path. Secret is the key for manual entry. OpenInApp is an otpauth: link, for a phone that has no second screen to scan. Code is the first code from the app, cleared after every try. Enable is the form's one submit.
Props
2 documented props · Native <svg> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/qr.tsx
User.TwoFactor.Secretcontent
Qr is an <svg> drawn locally as one currentColor path. Secret is the key for manual entry. OpenInApp is an otpauth: link, for a phone that has no second screen to scan. Code is the first code from the app, cleared after every try. Enable is the form's one submit.
Props
2 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/secret.tsx
User.TwoFactor.Codeinput · <input>
Qr is an <svg> drawn locally as one currentColor path. Secret is the key for manual entry. OpenInApp is an otpauth: link, for a phone that has no second screen to scan. Code is the first code from the app, cleared after every try. Enable is the form's one submit.
Required scope
User.TwoFactor.Code must be inside <User.TwoFactor.Form>.
Props
2 documented props · Native <input> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { invalid: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/code.tsx
User.TwoFactor.Enableaction · <button>
Qr is an <svg> drawn locally as one currentColor path. Secret is the key for manual entry. OpenInApp is an otpauth: link, for a phone that has no second screen to scan. Code is the first code from the app, cleared after every try. Enable is the form's one submit.
Required scope
User.TwoFactor.Enable must be inside <User.TwoFactor.Form>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/enable.tsx
User.TwoFactor.BackupCodecontent · <li>
ShowCodes moves from the success step to the codes. BackupCode is an <li> repeated once per code, with { code }, while the setup that brought them is on screen. CopyCodes gets { copied, failed }; DownloadCodes is an <a download> with a data: URL; PrintCodes prints them. CodesStored is the checkbox that says they are kept somewhere safe, and Finish waits for it, since the codes are shown once. Regenerate asks for a new set, and every old code stops working.
Capability: backup-codes
Props
2 documented props · Native <li> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { code: string }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/backup-code.tsx
User.TwoFactor.Regenerateaction · <button>
A new set of backup codes. Each old one stops working, which is the point: an account that has spent its way through the set it was given at setup has nothing left to use.
Capability: backup-codes
Required scope
User.TwoFactor.Regenerate must be inside <User.TwoFactor.Form>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/regenerate.tsx
User.TwoFactor.Disableaction · <button>
From the on state. Replace, Remove and NewCodes each pass through confirm. Disable turns two-factor off from a password outside the wizard. Error is <div role="alert"> with { code, message }, the last failure of starting, enabling, disabling, new codes or adding a password.
Required scope
User.TwoFactor.Disable must be inside <User.TwoFactor.Form>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/disable.tsx
User.TwoFactor.Errorcontent · <div>
From the on state. Replace, Remove and NewCodes each pass through confirm. Disable turns two-factor off from a password outside the wizard. Error is <div role="alert"> with { code, message }, the last failure of starting, enabling, disabling, new codes or adding a password.
Props
2 documented props · Native <div> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { code: AuthErrorCode; message: string }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/error.tsx
User.TwoFactor.Beginaction · <button>
Starts setting an authenticator up, which asks for the password first.
Required scope
User.TwoFactor.Begin must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/begin.tsx
User.TwoFactor.Accountinput · <input>
The address the authenticator will be set up for, read-only. Shown because a password prompt with no account beside it is a question about which account, and `autocomplete=username` is what lets a password manager offer the right password for the field underneath.
Required scope
User.TwoFactor.Account must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <input> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/account.tsx
User.TwoFactor.UseAnotherAccountaction · <button>
Signs out from the confirm step. Somebody who does not know this account's password is usually somebody looking at the wrong account, and the only way on from there is out.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/use-another-account.tsx
User.TwoFactor.Confirmaction · <button>
The password, for whatever the wizard was asked for. One part rather than four, because from the person's side this is one act: proving the account is theirs before anything about how they sign in changes.
Required scope
User.TwoFactor.Confirm must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/confirm.tsx
User.TwoFactor.Cancelaction · <button>
Leaves the wizard, forgetting the secret this browser was shown.
Required scope
User.TwoFactor.Cancel must be inside <User.TwoFactor.Root>.
User.TwoFactor.Cancel requires User.TwoFactor.Root.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/cancel.tsx
User.TwoFactor.OpenInAppcontent · <a>
The `otpauth:` link the authenticator app registered itself for. On a phone there is no second screen to point a camera at, so scanning is impossible and the link is the only way in short of typing the secret.
Props
2 documented props · Native <a> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/open-in-app.tsx
User.TwoFactor.ShowCodesaction · <button>
Leaves the success step for the recovery codes, which are shown once. Where a backend hands out none it is the way out of the wizard instead: the step after this one would be empty, and there would be nothing to press on it.
Capability: backup-codes
Required scope
User.TwoFactor.ShowCodes must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/show-codes.tsx
User.TwoFactor.CopyCodesaction · <button>
ShowCodes moves from the success step to the codes. BackupCode is an <li> repeated once per code, with { code }, while the setup that brought them is on screen. CopyCodes gets { copied, failed }; DownloadCodes is an <a download> with a data: URL; PrintCodes prints them. CodesStored is the checkbox that says they are kept somewhere safe, and Finish waits for it, since the codes are shown once. Regenerate asks for a new set, and every old code stops working.
Capability: backup-codes
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { copied: boolean; failed: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/copy-codes.tsx
User.TwoFactor.DownloadCodescontent · <a>
The codes as a file. A `data:` URL rather than a blob one, because a blob URL has to be revoked and an anchor nobody clicks would leak it for the life of the page.
Capability: backup-codes
Props
2 documented props · Native <a> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/download-codes.tsx
User.TwoFactor.PrintCodesaction · <button>
Paper, which is the one place a recovery code survives losing the phone and the laptop.
Capability: backup-codes
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/print-codes.tsx
User.TwoFactor.CodesStoredinput · <input>
Says the codes are somewhere safe, which is what finishes setup.
Capability: backup-codes
Required scope
User.TwoFactor.CodesStored must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <input> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { checked: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/codes-stored.tsx
User.TwoFactor.Finishaction · <button>
ShowCodes moves from the success step to the codes. BackupCode is an <li> repeated once per code, with { code }, while the setup that brought them is on screen. CopyCodes gets { copied, failed }; DownloadCodes is an <a download> with a data: URL; PrintCodes prints them. CodesStored is the checkbox that says they are kept somewhere safe, and Finish waits for it, since the codes are shown once. Regenerate asks for a new set, and every old code stops working.
Capability: backup-codes
Required scope
User.TwoFactor.Finish must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/finish.tsx
User.TwoFactor.Replaceaction · <button>
Swaps the authenticator for another one, by turning this one off and setting one up again: Better Auth keeps one TOTP per account and refuses a second with TOTP_ALREADY_ENABLED, so there is no one-step replacement to offer.
Required scope
User.TwoFactor.Replace must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/replace.tsx
User.TwoFactor.Removeaction · <button>
Asks to turn the authenticator off, which is confirmed with the password.
Required scope
User.TwoFactor.Remove must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/remove.tsx
User.TwoFactor.NewCodesaction · <button>
Asks for a new set of recovery codes. Each code is spent when it is used, so an account that has worked its way through the set it was given has no way back in left.
Required scope
User.TwoFactor.NewCodes must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/new-codes.tsx
User.TwoFactor.Providercontent
Who this account signs in through, so the explanation can name them rather than say "a provider". The ids come out as the backend spells them, `google` and `github`, and whoever writes the sentence gives them their capital letters.
Capability: methods: password
Props
2 documented props
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { provider: string | null; providers: readonly string[] }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/provider.tsx
User.TwoFactor.NewPasswordinput · <input>
The password an account that arrived through a provider is being given.
Capability: methods: password
Required scope
User.TwoFactor.NewPassword must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <input> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { invalid: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/new-password.tsx
User.TwoFactor.AddPasswordaction · <button>
Gives the account a password, which is what makes a second factor possible for it: the code is asked for on a password sign-in, and there was no password sign-in before this.
Capability: methods: password
Required scope
User.TwoFactor.AddPassword must be inside <User.TwoFactor.Root>.
Props
2 documented props · Native <button> attributes supported
| Prop | Type | Default |
|---|---|---|
childrenContent rendered inside this part. | ReactNode | ((state: { pending: boolean }) => ReactNode) | — |
renderReplace the default element with your own while retaining the part’s behavior and accessibility. | ReactElement | — |
Required props are marked. A dash means no explicit default is declared in this component.
Source: @slices.sh/auth/src/headless/two-factor/add-password.tsx
User.Rootscope
Says which auth the User parts below read, and whether they may do without it. The parts need no root: left out, they read the nearest auth root's config, or "default", and render nothing without auth. `<User.Root enabled="optional">` is for the one who wants that said in the code.
Props
3 documented props
| Prop | Type | Default |
|---|---|---|
configThe auth config, a slug from the registry ( | string | — |
enabledLeft out or | Enabled | — |
childrenContent rendered inside this part. | ReactNode | — |
Required props are marked. A dash means no explicit default is declared in this component.
Alternate public imports
User.Rootfrom@slices.sh/auth/headless/userUser.Rootfrom@slices.sh/auth/headless/passkeysUser.Rootfrom@slices.sh/auth/headless/two-factor
Source: @slices.sh/auth/src/headless/user/root.tsx
When something is missing
- No service configuration
- Install the auth setup below and import "@/services". Required service roots report missing setup; gates do not replace that configuration.
- Missing capability or parent scope
- Follow each part’s context requirements and the example composition. Capability-aware controls hide when the provider cannot perform their action.