Skip to main content

Auth State and User Data

Read session state and query application profile data from the correct owner.

useConvexAuth() answers whether a usable identity exists and exposes the session user. Product profile data remains an ordinary typed Convex query.

Auth state

ts
const { status, isPending, user, error, client, ready } = useConvexAuth()

status describes the current usable identity. isPending describes auth work in flight. Keep them separate in UI logic.

Use these app-lifetime refs for route identity. On the pinned Better Auth tuple, do not mount client.useSession() in route components; remounting its auth-query atom can leave session state stale. client is the one integrated Better Auth client for sign-in, sign-out, and inferred plugin methods. It is null during SSR, so call it from browser-owned handlers after checking availability.

vue
<template>
  <p v-if="status === 'loading'">Checking session…</p>
  <p v-else-if="status === 'error'">{{ error?.message ?? 'Authentication failed' }}</p>
  <p v-else-if="status === 'authenticated'">Welcome, {{ user?.name ?? user?.email }}</p>
  <SignInLink v-else-if="status === 'anonymous'" />
</template>

Choose a user-data source

DataSource
Name/email needed immediately during SSRuseConvexAuth().user
Product profile, preferences, searchable display dataExplicit application projection query
Small identity fields needed in every Convex functionJWT claims
Roles and memberships used for authorizationCanonical backend data checked per function

Do not put frequently changing permissions only in JWT claims. Their value can remain stale until token refresh.

Query a product profile directly

ts
const auth = useConvexAuth()
const profile = useConvexQuery(api.users.getCurrentProfile, {}, { auth: 'required' })

const displayName = computed(
  () => profile.data.value?.displayName ?? auth.user.value?.name ?? 'Account',
)

The session remains the immediate auth source. The projection remains application-owned Convex data with its own schema, indexes, synchronization, and rebuild story. undefined means the profile query has no value yet; a backend null result is a successful “no profile” result.