Skip to main content

Sign In and Sign Out

Run integrated Better Auth operations and handle their identity lifecycle.

useConvexAuth() exposes the Better Auth client namespaces through the module's identity coordinator.

Email sign-in

ts
const { signIn, isPending } = useConvexAuth()

const result = await signIn.email({
  email: email.value,
  password: password.value,
})

if (result.error) {
  formError.value = 'Sign in could not be completed'
}

Do not display raw credential errors if they reveal whether an account exists.

Sign-up

ts
const result = await signUp.email({
  name: name.value,
  email: email.value,
  password: password.value,
})

The result depends on the Better Auth server options: email verification and autoSignIn determine the next product step.

Sign-out

ts
const { signOut } = useConvexAuth()

await signOut()
await navigateTo('/')

The application owns navigation. The auth coordinator owns session operation ordering, identity transition, query-state isolation, and client replacement.

Wait for settlement

Use ready() outside normal query gating when an application workflow must await initial auth settlement:

ts
const status = await useConvexAuth().ready({ timeoutMs: 5_000 })

Queries already implement their own auth-mode gating. Do not call ready() before every query.

Refresh

refresh() resolves the current session/token state. Concurrent refreshes are deduplicated within the current auth epoch. A later sign-in or sign-out cannot be overwritten by an older refresh result.

Operation state versus identity state

isPending can be true while status remains authenticated. Keep the current authenticated UI visible during a background refresh unless the product has a specific reason to block it.

Failures across identity changes

An in-flight mutation, action, or imperative call tied to the previous identity rejects with IDENTITY_CHANGED. The UI should stop presenting its result under the new user. Do not automatically retry a write because it may already have committed.