Mutations
TanStack Query primitives for every Better Auth write endpoint.
React provides mutation hooks. Core provides the shared options factories. Each factory exposes its canonical key through .mutationKey.
import { authClient } from "@/lib/auth-client"
import { signInEmailOptions } from "@better-auth-ui/core"
import { useSignInEmail } from "@better-auth-ui/react"Use the hook in components. Use the core factory where TanStack Query accepts a mutationOptions object.
Error handling
Each mutation adds throw: true to fetchOptions. The promise rejects with BetterFetchError instead of resolving with { error }.
You can therefore use the standard error, isError, throwOnError, and onError values from useMutation.
const { mutate, error } = useSignInEmail(authClient, {
onError: (err) => toast.error(err.message)
})Cache side effects
Hooks that change authentication state also update the cache. A custom onSuccess handler runs after the built-in cache update:
useSignInEmail/useSignInUsername/useSignInPasskey/useSignUpEmail: reset the session query so it retrieves the new session.useSignInSocial/useSignInMagicLink: redirect without a cache update.useSignOut: remove every["auth", ...]query.useUpdateUser: update the current user's profile fields and refresh the cached session.useSetActiveSession: update the cached session, scroll to the top, and refresh the session queries.useChangeEmail/useChangeEmailOtp: refresh the session.useSignInEmailOtp/useVerifyEmailOtp: refresh the session because both operations create one.useVerifyTotp/useVerifyTwoFactorOtp/useVerifyBackupCode: refresh the session after the second factor creates it.useEnableTwoFactor/useDisableTwoFactor: refresh the session to updateuser.twoFactorEnabled.useAddPasskey/useDeletePasskey: refresh the passkey list.useRevokeSession: refresh the sessions list.useRevokeMultiSession: refresh the device sessions list.useUnlinkAccount: refresh the linked accounts list.
Tracking mutation state globally
All mutation keys start with "auth". The shared authMutationKeys factory in @better-auth-ui/core exposes these keys.
Use this factory instead of inline tuples. Call sites and mutation factories will then use the same keys:
import { authMutationKeys } from "@better-auth-ui/core"
import { useIsMutating } from "@tanstack/react-query"
const authPending = useIsMutating({ mutationKey: authMutationKeys.all })
const signInPending = useIsMutating({ mutationKey: authMutationKeys.signIn.all })
const emailSignInPending = useIsMutating({
mutationKey: authMutationKeys.signIn.email
})Each grouping (signIn, signUp, passkey, multiSession) exposes an all prefix so you can match a whole feature at once.
Match inside a MutationCache observer for global toasts or analytics:
import { authMutationKeys } from "@better-auth-ui/core"
new MutationCache({
onError: (error, _vars, _ctx, mutation) => {
if (mutation.options.mutationKey?.[0] === authMutationKeys.all[0]) {
toast.error(error.message)
}
}
})Escape hatch
Use useAuthMutation for a mutation endpoint that has no specific hook. Use useAuthQuery for a read endpoint.
import { authClient } from "@/lib/auth-client"
import { useAuthMutation } from "@better-auth-ui/react"
const { mutate } = useAuthMutation(
authClient.emailOtp.sendVerificationOtp,
["auth", "emailOtp", "sendVerificationOtp"]
)
mutate({ email: "user@example.com", type: "sign-in" })TypeScript infers variables from the authFn parameter. Required parameters prevent an empty mutate() call, while optional parameters permit it.
The factory adds throw: true to fetchOptions. Therefore, onError and error receive a BetterFetchError.
For shared mutation registration (useIsMutating, a global MutationCache observer, manual useMutation), import the endpoint's option factory from core and use it directly:
import { changePasswordOptions } from "@better-auth-ui/core"
import { useMutation } from "@tanstack/react-query"
const { mutate } = useMutation(changePasswordOptions(authClient))For endpoints that already have a key in authMutationKeys, prefer it over an inline tuple so cache observers and useIsMutating checks line up.
Available mutations
Auth
useSignInEmail
useSignInUsername
useSignInMagicLink
useSignInPasskey
useSignInSocial
useSignUpEmail
useSignOut
useRequestPasswordReset
useResetPassword
useSendVerificationEmail
useIsUsernameAvailable
useOAuthConsent
useVerifyDeviceCode
useApproveDevice
useDenyDevice
Settings
useUpdateUser
useChangeEmail
useChangePassword
useDeleteUser
useLinkSocial
useUnlinkAccount
useAddPasskey
useDeletePasskey
useRevokeSession
useRevokeMultiSession
useSetActiveSession
useCreateApiKey
useDeleteApiKey
Organization
Last updated on