Client-side authentication
Choose an API
| Need | API |
|---|---|
| Session state and lifecycle actions | useUserSession() |
| Direct Better Auth client or plugin methods | useAuthClient() |
| Sign-in or sign-up form state | useSignIn() or useSignUp() |
| Action state for a client or plugin method | useAuthClientAction() |
| Action state for any async function | useAction() |
| Refresh session state after a custom auth endpoint | runWithSessionRefresh() |
| Request-scoped auth fetch with typed endpoints | useAuthRequestFetch() |
| SSR-safe auth-bound data | useAuthAsyncData() |
useUserSessionState() is a deprecated alias for useUserSession().
Session state and direct client access
const { user, session, loggedIn, ready, fetchSession, signOut, updateUser } = useUserSession()
const client = useAuthClient()useUserSession() is safe to return from a Pinia setup store. useAuthClient() returns the client in the browser and null during SSR.
Sign-in and sign-up forms
Use action composables for form flows that need loading, error, and success state.
const signInEmail = useSignIn('email')
await signInEmail.execute({
email: 'user@example.com',
password: 'password123',
})const signUpEmail = useSignUp('email')
await signUpEmail.execute({ email, password, name })If no onSuccess callback is passed, sign-in and sign-up can redirect to a safe local ?redirect=... target or the configured authenticated redirect.
Plugin client actions
Use useAuthClientAction() for Better Auth client/plugin methods that should expose action state.
const openPortal = useAuthClientAction(client => client.customer.portal)
await openPortal.execute()Use useAction() for the same action state around an arbitrary async function.
Custom auth endpoints
Use runWithSessionRefresh() around custom endpoints that create or change the current session.
await runWithSessionRefresh(() =>
$fetch('/api/custom-login', {
method: 'POST',
body: { email, password },
}),
)The helper awaits your request, then refreshes local session state unless the result is a Better Auth action error result.
Auth-bound data
Use useAuthRequestFetch() for low-level request control. During SSR it forwards the request context, including cookies.
The endpoint below comes from a configured custom customer plugin. Replace it with an endpoint generated by the consumer's Better Auth config.
const requestFetch = useAuthRequestFetch()
const customerState = await requestFetch('/api/auth/customer/state')Use useAuthAsyncData() for keyed SSR data with Nuxt loading and error state. It requires an authenticated user by default and resolves to null without calling the endpoint when the user is signed out.
const { data, pending, error } = await useAuthAsyncData(
'customer-state',
requestFetch => requestFetch('/api/auth/customer/state'),
)Force refresh
await fetchSession({ force: true })Use force: true when the server-side session payload changed and Better Auth's cookie cache should be bypassed for this fetch.
Redirect rule
If you read route.query.redirect, validate it before navigating. Only allow local paths.
BetterAuthState
<BetterAuthState> renders once session hydration completes (ready === true) and supports a loading placeholder.
<BetterAuthState>
<template #default="{ loggedIn, user, signOut }">
<p v-if="loggedIn">Hi {{ user?.name }}</p>
<button v-else @click="navigateTo('/login')">Sign in</button>
</template>
<template #placeholder>
<p>Loading...</p>
</template>
</BetterAuthState>