Client setup
Create a typed Better Auth client for your frontend.
payload-auth does not ship its own client. You use the standard Better Auth client, which
talks to the route handler you mounted at /api/auth/[...all].
Create the client
import { createAuthClient } from 'better-auth/react'
import {
adminClient,
inferAdditionalFields,
twoFactorClient,
} from 'better-auth/client/plugins'
import { betterAuthOptions } from './options'
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL,
plugins: [
adminClient(),
twoFactorClient(),
inferAdditionalFields({
user: { role: { type: 'string' } },
}),
],
$InferAuth: betterAuthOptions,
})
export const { signIn, signUp, signOut, useSession } = authClientTwo rules to keep in mind:
- Client plugins mirror server plugins. Every Better Auth plugin that adds client
methods needs its matching
*Client()entry here. - Pass
$InferAuth. Handing yourbetterAuthOptionsto the client gives you typed sessions, users and plugin methods without importing server code into the browser.
Use it
'use client'
import { authClient } from '@/lib/auth/client'
export function SignIn() {
const { data: session, isPending } = authClient.useSession()
if (isPending) return null
if (session) {
return (
<button onClick={() => authClient.signOut()}>
Sign out {session.user.email}
</button>
)
}
return (
<button
onClick={() =>
authClient.signIn.social({ provider: 'google', callbackURL: '/dashboard' })
}
>
Continue with Google
</button>
)
}Everything else — signIn.email, signUp.email, organization.*, passkey.* — is
plain Better Auth. See the
Better Auth client docs.
The role field
payload-auth stores role as a Payload multi-select field, so on the session object it
is a string array, not a string:
const { data: session } = authClient.useSession()
session?.user.role // e.g. ['admin']The exported BetterAuthReturn['$Infer']['Session'] type reflects this. If you use the
Better Auth admin plugin, its role checks still work — the plugin's middleware
normalises between the two shapes.
Server-side access
On the server, skip the HTTP client and call the auth instance directly:
import { headers } from 'next/headers'
import { getPayload } from '@/lib/payload'
const payload = await getPayload()
const session = await payload.betterAuth.api.getSession({ headers: await headers() })See Server-side usage for the full picture.