客户端

了解如何为 React、Vue、Svelte 和其他框架设置 Better Auth 客户端、使用钩子、配置 fetch 选项、处理错误,以及通过客户端插件进行扩展

Better Auth 提供了一个与流行前端框架(如 React、Vue、Svelte 等)兼容的客户端库。该客户端库包含一组用于与 Better Auth 服务器交互的函数。每个框架的客户端库都建立在一个与框架无关的核心客户端库之上,因此所有方法和钩子在所有客户端库中均保持一致。

安装

如果尚未安装,请先安装 better-auth。

npm i better-auth

创建客户端实例

从你所用的框架的包中导入 createAuthClient(例如 React 框架使用 "better-auth/react")。调用该函数创建你的客户端。传入你身份验证服务器的基础 URL。如果身份验证服务器与客户端运行在同一域上,则可以跳过此步骤。

如果你的身份验证服务器使用的基础路径不是 /api/auth,你可以传入包含路径的完整 URL(例如 http://localhost:3000/custom-path/auth),也可以单独使用 basePath 选项

lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
    baseURL: "http://localhost:3000" // The base URL of your auth server
})

使用方法

创建客户端实例后,你可以使用该客户端与 Better Auth 服务器交互。客户端默认提供一组函数,也可以使用插件进行扩展。

示例:登录

auth-client.ts
import { createAuthClient } from "better-auth/client"
const authClient = createAuthClient()

await authClient.signIn.email({
    email: "[email protected]",
    password: "password1234"
})

钩子

除了标准方法外,客户端还提供钩子以便轻松访问不同的响应式数据。每个钩子都在客户端根对象中可用,且名称都以 use 开头。

示例:useSession

user.tsx
//make sure you're using the react client
import { createAuthClient } from "better-auth/react"
const { useSession } = createAuthClient() 

export function User() {
    const {
        data: session,
        isPending, //loading state
        error, //error object 
        refetch //refetch the session
    } = useSession()
    return (
        //...
    )
}

请求选项

客户端使用一个名为 better fetch 的库向服务器发出请求。

Better fetch 是对原生 fetch API 的封装,提供了更方便的请求方式。它由 Better Auth 团队创建,设计上与 Better Auth 无缝配合。

你可以通过传递 fetchOptions 对象给 createAuthClient,为客户端设置默认的 fetch 选项。

auth-client.ts
import { createAuthClient } from "better-auth/client"

const authClient = createAuthClient({
    fetchOptions: {
        // 任何 better-fetch 的选项
    },
})

禁用默认的 Fetch 插件

身份验证客户端包含默认的 fetch 插件,用于处理浏览器特有的行为,比如自动重定向。对于非浏览器环境(例如 React Native/Expo),你可以通过设置 disableDefaultFetchPluginstrue 来禁用这些插件:

auth-client.ts
import { createAuthClient } from "better-auth/client"

const authClient = createAuthClient({
    disableDefaultFetchPlugins: true,
})

你也可以将 fetch 选项传递给大多数客户端函数,作为第二个参数,或者作为对象中的属性。

import { authClient } from "@/lib/auth-client"

await authClient.signIn.email({
    email: "[email protected]",
    password: "password1234",
}, {
    onSuccess(ctx) {
            //      
    }
})

//或

await authClient.signIn.email({
    email: "[email protected]",
    password: "password1234",
    fetchOptions: {
        onSuccess(ctx) {
            //      
        }
    },
})

会话选项

你可以使用 sessionOptions 选项配置客户端处理会话获取和重新验证的方式。

auth-client.ts
import { createAuthClient } from "better-auth/client"

const authClient = createAuthClient({
    sessionOptions: {
        refetchInterval: 0,
        refetchOnWindowFocus: true,
        refetchWhenOffline: false,
    }
})

Prop

Type

禁用默认 Fetch 插件

客户端包含一个默认的重定向插件,用于处理身份验证重定向。如果你需要禁用此行为,可以将 disableDefaultFetchPlugins 设置为 true

auth-client.ts
import { createAuthClient } from "better-auth/client"

const authClient = createAuthClient({
    disableDefaultFetchPlugins: true
})

禁用钩子重新渲染

某些端点在成功响应后,会触发 atom 信号,导致像 useSession 的钩子重新渲染。 这对于让你的 UI 与身份验证状态保持同步非常有用。

但是,有时你可能想要调用端点而不触发钩子重新渲染。 例如,更新不会影响 session 的用户偏好时,或者你想手动控制钩子何时更新。

你可以通过在 fetch 选项中设置 disableSignal: true,禁用特定端点调用的钩子重新渲染:

import { authClient } from "@/lib/auth-client"

// 作为第二个参数
await authClient.updateUser({
    name: "New Name"
}, {
    disableSignal: true
})

// 或者在 fetchOptions 中
await authClient.updateUser({
    name: "New Name",
    fetchOptions: {
        disableSignal: true
    }
})

disableSignal 设置为 true 时,端点调用会成功完成, 但像 useSession 这样的钩子不会自动重新渲染。你可以根据需要手动触发重新获取:

import { authClient } from "@/lib/auth-client"

const { refetch } = authClient.useSession()

await authClient.updateUser({
    name: "New Name"
}, {
    disableSignal: true,
    onSuccess() {
        // 如果需要,手动重新获取 session
        refetch()
    }
})

错误处理

大多数客户端函数都会返回一个包含以下属性的响应对象:

  • data:响应数据
  • error:如果发生错误,则为错误对象

错误对象包含以下属性:

  • message:错误消息(例如:“Invalid email or password”)
  • status:HTTP 状态码
  • statusText:HTTP 状态文本
import { authClient } from "@/lib/auth-client"

const { data, error } = await authClient.signIn.email({
    email: "[email protected]",
    password: "password1234"
})
if (error) {
    // 处理错误
}

如果动作支持 fetchOptions 选项,你可以传入 onError 回调来处理错误。

import { authClient } from "@/lib/auth-client"

await authClient.signIn.email({
    email: "[email protected]",
    password: "password1234",
}, {
    onError(ctx) {
        // 处理错误
    }
})

// 或者
await authClient.signIn.email({
    email: "[email protected]",
    password: "password1234",
    fetchOptions: {
        onError(ctx) {
            // 处理错误
        }
    }
})

useSession 这样的钩子也会返回错误对象(如果获取 session 失败),此外还返回 isPending 属性以指示请求是否仍在进行中。

import { useSession } from "@/lib/auth-client"

const { data, error, isPending } = useSession()
if (error) {
    // 处理错误
}

错误代码

客户端实例包含 $ERROR\_CODES 对象,其中包含服务器返回的所有错误代码。你可以使用它来处理错误翻译或自定义错误消息。

auth-client.ts
const authClient = createAuthClient();

type ErrorTypes = Partial<
	Record<
		keyof typeof authClient.$ERROR_CODES,
		{
			en: string;
			es: string;
		}
	>
>;

const errorCodes = {
	USER_ALREADY_EXISTS: {
		en: "user already registered",
		es: "usuario ya registrado",
	},
} satisfies ErrorTypes;

const getErrorMessage = (code: string, lang: "en" | "es") => {
	if (code in errorCodes) {
		return errorCodes[code as keyof typeof errorCodes][lang];
	}
	return "";
};


const { error } = await authClient.signUp.email({
	email: "[email protected]",
	password: "password",
	name: "User",
});
if(error?.code){
    alert(getErrorMessage(error.code, "en"));
}

SSR Hydration

对于 Next.js、Nuxt 或 SvelteKit 等 SSR 框架,useSession 会在客户端获取 session,从而导致加载闪烁。将服务器获取的 session 传递给 hydrateSession 并将其用作回退值,这样首次渲染时服务器和客户端都有数据:

page.tsx (server component)
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { SessionCard } from "./session-card"

export default async function Page() {
    const session = await auth.api.getSession({
        headers: await headers(),
    })
    return <SessionCard initialSession={session} />
}
session-card.tsx (client component)
"use client"

import { authClient } from "@/lib/auth-client"

type Props = {
    initialSession: typeof authClient.$Infer.Session | null
}

export function SessionCard({ initialSession }: Props) {
    authClient.hydrateSession(initialSession)
    const { data, isPending, isRefetching } = authClient.useSession()
    const session = isPending && !isRefetching ? initialSession : data

    if (!session) return <p>未登录</p>
    return <pre>{JSON.stringify(session, null, 2)}</pre>
}
  • 只有第一次传入非 null 值的 hydrateSession 调用会生效
  • 传入 null 是安全的。它会被忽略,useSession 将照常获取

插件

你可以使用插件扩展客户端,以添加更多功能。插件可以向客户端添加新函数或修改现有函数。

示例:Magic Link 插件

auth-client.ts
import { createAuthClient } from "better-auth/client"
import { magicLinkClient } from "better-auth/client/plugins"

const authClient = createAuthClient({
    plugins: [
        magicLinkClient()
    ]
})

添加插件后,你可以使用插件提供的新函数。

import { authClient } from "@/lib/auth-client"

await authClient.signIn.magicLink({
    email: "[email protected]"
})