useUser() hook

useUser() is the broadest user-management hook in the shared client layer. It owns the current user record together with the mutations for profile updates, contact methods, authenticators, backup codes, passwords, social connections, and passkeys.

Usage

The following example shows a basic usage of useUser().

export default function ProfileSettings() {  const { user, loading, updateProfile } = useUser();  if (loading) {    return null;  }  async function save() {    await updateProfile({      first_name: user.first_name,      last_name: user.last_name,    });  }  return <button onClick={save}>Save profile</button>;}

Return value

The hook returns the following fields and methods.

user: CurrentUser & { refetch: () => Promise<CurrentUser | undefined> };
The current user record together with a `refetch()` helper from the underlying SWR cache.
id?: string | undefined;
The current user identifier.
first_name?: string | undefined;
The user first name.
last_name?: string | undefined;
The user last name.
username?: string | undefined;
The username when one is set.
primary_email_address?: UserEmailAddress | undefined;
The primary email address record.
email?: string | undefined;
The email address value.
verified?: boolean | undefined;
Whether the email address has been verified.
primary_phone_number?: UserPhoneNumber | undefined;
The primary phone number record when one exists.
phone_number?: string | undefined;
The phone number value.
verified?: boolean | undefined;
Whether the phone number has been verified.
user_email_addresses?: UserEmailAddress[] | undefined;
All email addresses attached to the current user.
user_phone_numbers?: UserPhoneNumber[] | undefined;
All phone numbers attached to the current user.
social_connections?: SocialConnection[] | undefined;
The currently linked social accounts.
user_authenticator?: UserAuthenticator | undefined;
The current authenticator record when one exists.
backup_codes_generated?: boolean | undefined;
Whether backup codes have already been generated.
has_password?: boolean | undefined;
Whether the current user has a password set.
has_passkeys?: boolean | undefined;
Whether the current user has passkeys registered.
refetch?: () => Promise<CurrentUser | undefined> | undefined;
Refreshes the current user record.
loading: boolean;
Whether the user record is still loading.
error: Error | null;
The user-loading error, if one occurred.
updateProfile: (data: ProfileUpdateData) => Promise<ApiResult<unknown>>;
Updates the core profile fields, primary contact IDs, second-factor policy, or profile-picture removal flag.
first_name?: string | undefined;
The new first name.
last_name?: string | undefined;
The new last name.
username?: string | undefined;
The new username.
primary_email_address_id?: string | undefined;
The email address to make primary.
primary_phone_number_id?: string | undefined;
The phone number to make primary.
second_factor_policy?: "none" | "optional" | "enforced" | undefined;
The second-factor policy for the current user.
remove_profile_picture?: boolean | undefined;
Whether the current profile picture should be removed.
getEmailAddresses: () => Promise<ApiResult<UserEmailAddress[]>>;
Loads all email addresses attached to the current user.
[].id?: string | undefined;
Email-address record identifier.
[].email?: string | undefined;
Email address value.
[].is_primary?: boolean | undefined;
Whether the address is currently primary.
[].verified?: boolean | undefined;
Whether the address has been verified.
[].verified_at?: string | undefined;
Verification timestamp when the address has been verified.
[].verification_strategy?: "otp" | "oath_google" | "oath_github" | "oauth_microsoft" | "oauth_facebook" | "oauth_linkedin" | "oauth_discord" | "oauth_apple" | undefined;
Verification strategy attached to the address.
getEmailAddress: (id: string) => Promise<ApiResult<UserEmailAddress>>;
Loads one specific email-address record for the current user.
id?: string | undefined;
Email-address record identifier.
email?: string | undefined;
Email address value.
is_primary?: boolean | undefined;
Whether the address is currently primary.
verified?: boolean | undefined;
Whether the address has been verified.
verified_at?: string | undefined;
Verification timestamp when the address has been verified.
verification_strategy?: "otp" | "oath_google" | "oath_github" | "oauth_microsoft" | "oauth_facebook" | "oauth_linkedin" | "oauth_discord" | "oauth_apple" | undefined;
Verification strategy attached to the address.
createEmailAddress: (email: string) => Promise<ApiResult<UserEmailAddress>>;
Creates a new email address for the current user.
id?: string | undefined;
Email-address record identifier.
email?: string | undefined;
Email address value.
is_primary?: boolean | undefined;
Whether the address is currently primary.
verified?: boolean | undefined;
Whether the address has been verified.
verified_at?: string | undefined;
Verification timestamp when the address has been verified.
verification_strategy?: "otp" | "oath_google" | "oath_github" | "oauth_microsoft" | "oauth_facebook" | "oauth_linkedin" | "oauth_discord" | "oauth_apple" | undefined;
Verification strategy attached to the address.
deleteEmailAddress: (id: string) => Promise<ApiResult<unknown>>;
Deletes an existing email address.
prepareEmailVerification: (id: string) => Promise<ApiResult<unknown>>;
Starts verification for an email address.
attemptEmailVerification: (id: string, otp: string) => Promise<ApiResult<unknown>>;
Submits an email verification code.
makeEmailPrimary: (id: string) => Promise<ApiResult<unknown>>;
Makes an email address primary.
createPhoneNumber: (phone_number: string, country_code: string) => Promise<ApiResult<UserPhoneNumber>>;
Creates a new phone number for the current user.
id?: string | undefined;
Phone-number record identifier.
phone_number?: string | undefined;
Phone number value.
country_code?: string | undefined;
Phone country code stored with the number.
verified?: boolean | undefined;
Whether the number has been verified.
verified_at?: string | undefined;
Verification timestamp when the number has been verified.
deletePhoneNumber: (id: string) => Promise<ApiResult<unknown>>;
Deletes an existing phone number.
preparePhoneVerification: (id: string) => Promise<ApiResult<unknown>>;
Starts verification for a phone number.
attemptPhoneVerification: (id: string, otp: string) => Promise<ApiResult<unknown>>;
Submits a phone verification code.
makePhonePrimary: (id: string) => Promise<ApiResult<unknown>>;
Makes a phone number primary.
setupAuthenticator: () => Promise<UserAuthenticator>;
Creates an authenticator enrollment and returns the TOTP setup data.
id?: string | undefined;
Authenticator identifier.
created_at?: string | undefined;
Creation timestamp for the authenticator record.
totp_secret?: string | undefined;
TOTP secret when the setup flow exposes it.
otp_url?: string | undefined;
OTP provisioning URL for authenticator apps.
verifyAuthenticator: (id: string, codes: string[]) => Promise<ApiResult<unknown>>;
Verifies an authenticator using one or more codes.
deleteAuthenticator: (id: string) => Promise<ApiResult<unknown>>;
Deletes an authenticator enrollment.
generateBackupCodes: () => Promise<string[]>;
Generates backup codes for the current user.
regenerateBackupCodes: () => Promise<string[]>;
Regenerates backup codes for the current user.
updateProfilePicture: (file: File) => Promise<ApiResult<unknown>>;
Uploads a new profile picture for the current user.
updatePassword: (currentPassword: string, newPassword: string) => Promise<ApiResult<unknown>>;
Changes the current password.
removePassword: (currentPassword: string) => Promise<ApiResult<unknown>>;
Removes the current password when the deployment allows it.
connectSocialAccount: (params: { provider: string; redirectUri?: string }) => Promise<ApiResult<{ oauth_url: string }>>;
Starts a social-account connection flow in a new browser window.
oauth_url?: string | undefined;
Provider URL that the browser opens to continue the connection flow.
disconnectSocialConnection: (id: string) => Promise<ApiResult<unknown>>;
Disconnects an existing social connection.
getPasskeys: () => Promise<ApiResult<UserPasskey[]>>;
Lists the registered passkeys for the current user.
[].id?: string | undefined;
Passkey identifier.
[].name?: string | undefined;
Display name for the passkey.
[].created_at?: string | undefined;
Creation timestamp.
[].last_used_at?: string | null | undefined;
Last-used timestamp, or `null` when the passkey has not been used yet.
[].device_type?: string | undefined;
Device classification for the passkey.
[].backed_up?: boolean | undefined;
Whether the passkey is backed up by the platform authenticator.
registerPasskey: (name?: string) => Promise<ApiResult<unknown>>;
Starts and completes the browser WebAuthn registration flow for a new passkey.
renamePasskey: (id: string, name: string) => Promise<ApiResult<unknown>>;
Renames an existing passkey.
deletePasskey: (id: string) => Promise<ApiResult<unknown>>;
Deletes an existing passkey.
deleteAccount: (password: string) => Promise<ApiResult<unknown>>;
Deletes the current account after password confirmation.

How it works

The hook keeps the current user record in SWR and then layers a large set of user-owned mutations on top of the same deployment-aware client.
Not every mutation immediately mutates or revalidates the user cache. Profile updates, password removal, and a few other flows call mutate(), while other actions return their response and leave refresh timing to the caller.
Email addresses, phone numbers, authenticators, social connections, and passkeys are all managed from this one surface because they belong to the current user rather than to the current session.
Passkey registration is the most involved flow on the page. The hook begins registration with the backend, converts the returned challenge/options into WebAuthn browser types, calls navigator.credentials.create(), then posts the attestation payload back to finish registration.

When to use it

  • Use it when you need profile data or user-level mutations.
  • This is a broader surface than useSession(), which is focused on the session rather than the profile.

Examples

Update profile fields

export default function ProfileSettings() {  const { user, loading, updateProfile } = useUser();  if (loading) {    return null;  }  async function save() {    await updateProfile({      first_name: user.first_name,      last_name: user.last_name,    });  }  return <button onClick={save}>Save profile</button>;}

Add and verify an email address

export default function EmailManager() {  const { createEmailAddress, prepareEmailVerification, attemptEmailVerification } = useUser();  async function addEmail() {    const created = await createEmailAddress('new@example.com');    if ('data' in created) {      await prepareEmailVerification(created.data.id);      await attemptEmailVerification(created.data.id, '123456');    }  }  return <button onClick={addEmail}>Add email</button>;}

Add and verify a phone number

export default function PhoneManager() {  const { createPhoneNumber, preparePhoneVerification, attemptPhoneVerification } = useUser();  async function addPhone() {    const created = await createPhoneNumber('+14155550123');    if ('data' in created) {      await preparePhoneVerification(created.data.id);      await attemptPhoneVerification(created.data.id, '123456');    }  }  return <button onClick={addPhone}>Add phone</button>;}

Change the current password

export default function PasswordSettings() {  const { updatePassword } = useUser();  async function changePassword() {    await updatePassword('current-password', 'new-password');  }  return <button onClick={changePassword}>Change password</button>;}

Start a social connection flow

export default function ConnectGithub() {  const { connectSocialAccount } = useUser();  async function connect() {    const result = await connectSocialAccount({      provider: 'github',      redirectUri: window.location.href,    });    if ('data' in result) {      window.location.href = result.data.oauth_url;    }  }  return <button onClick={connect}>Connect GitHub</button>;}

Register a passkey

export default function PasskeyButton() {  const { registerPasskey } = useUser();  async function register() {    await registerPasskey('Laptop');  }  return <button onClick={register}>Register passkey</button>;}

Rename or remove an existing passkey

export default function PasskeyList() {  const { getPasskeys, renamePasskey, deletePasskey } = useUser();  async function renameFirstPasskey() {    const result = await getPasskeys();    if ('data' in result && result.data.length > 0) {      await renamePasskey(result.data[0].id, 'Main laptop');    }  }  async function removeFirstPasskey() {    const result = await getPasskeys();    if ('data' in result && result.data.length > 0) {      await deletePasskey(result.data[0].id);    }  }  return (    <div className="flex gap-3">      <button onClick={renameFirstPasskey}>Rename first passkey</button>      <button onClick={removeFirstPasskey}>Remove first passkey</button>    </div>  );}

On this page