基本用法

入门 Better Auth

Better Auth 提供内置的认证支持:

  • 邮箱和密码
  • 社交提供商(Google、GitHub、Apple 等)

同时也可以通过插件轻松扩展,例如:用户名魔法链接通行密钥邮箱验证码 等。

邮箱 & 密码

启用邮箱和密码认证:

auth.ts
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    emailAndPassword: {    
        enabled: true
    } 
})

注册

要注册用户,需要调用客户端方法 signUp.email 并传入用户信息。

sign-up.ts
import { authClient } from "@/lib/auth-client"; // 导入认证客户端

const { data, error } = await authClient.signUp.email({
        email, // 用户邮箱地址
        password, // 用户密码 -> 默认最少8个字符
        name, // 用户显示名称
        image, // 用户头像 URL(可选)
        callbackURL: "/dashboard" // 用户验证邮箱后跳转的 URL(可选)
    }, {
        onRequest: (ctx) => {
            // 显示加载中
        },
        onSuccess: (ctx) => {
            // 跳转到仪表盘或登录页
        },
        onError: (ctx) => {
            // 显示错误信息
            alert(ctx.error.message);
        },
});

默认情况下,用户注册成功后会自动登录。如需禁用此行为,可以将 autoSignIn 设置为 false

auth.ts
import { betterAuth } from "better-auth"

export const auth = betterAuth({
    emailAndPassword: {
    	enabled: true,
    	autoSignIn: false // 默认为 true
  },
})

登录

要登录用户,可以使用客户端提供的 signIn.email 函数。

sign-in
const { data, error } = await authClient.signIn.email({
        /**
         * 用户邮箱
         */
        email,
        /**
         * 用户密码
         */
        password,
        /**
         * 用户验证邮箱后跳转的 URL(可选)
         */
        callbackURL: "/dashboard",
        /**
         * 浏览器关闭后是否记住用户会话。
         * @default true
         */
        rememberMe: false
}, {
    // 回调函数
})

请始终在客户端调用客户端方法。不要在服务端调用它们。

服务器端认证

要在服务器端认证用户,可以使用 auth.api 方法。

server.ts
import { auth } from "./auth"; // 你的 Better Auth 服务器实例路径

const response = await auth.api.signInEmail({
    body: {
        email,
        password
    },
    asResponse: true // 返回响应对象而非数据
});

如果服务器无法直接返回响应对象,你需要手动解析并设置 cookie。但对于 Next.js 等框架,我们提供了插件自动处理该流程。

社交登录

Better Auth 支持多种社交提供商,包括 Google、GitHub、Apple、Discord 等。使用社交提供商时,需在 auth 对象的 socialProviders 选项中配置相应的提供商。

auth.ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
    socialProviders: { 
        github: { 
            clientId: process.env.GITHUB_CLIENT_ID!, 
            clientSecret: process.env.GITHUB_CLIENT_SECRET!, 
        } 
    }, 
})

使用社交提供商登录

要使用社交提供商登录,调用 signIn.social,并传入如下属性对象:

sign-in.ts
import { authClient } from "@/lib/auth-client"; //导入认证客户端

await authClient.signIn.social({
    /**
     * 社交提供商 ID
     * @example "github", "google", "apple"
     */
    provider: "github",
    /**
     * 用户通过提供商认证后重定向的 URL
     * @default "/"
     */
    callbackURL: "/dashboard", 
    /**
     * 登录过程中发生错误时重定向的 URL
     */
    errorCallbackURL: "/error",
    /**
     * 用户新注册时重定向的 URL
     */
    newUserCallbackURL: "/welcome",
    /**
     * 禁用自动跳转至提供商。
     * @default false
     */
    disableRedirect: true,
});

也可以使用社交提供商的 idTokenaccessToken 进行认证,而无需跳转到提供商网站。详情见社交提供商文档。

登出

要登出用户,可以使用客户端提供的 signOut 函数。

user-card.tsx
await authClient.signOut();

你也可以传入 fetchOptions 实现登出成功时跳转:

user-card.tsx
await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/login"); // 跳转到登录页
    },
  },
});

会话

用户登录后,你可能需要访问用户会话。Better Auth 支持在服务端和客户端轻松访问会话数据。

客户端

使用会话

Better Auth 提供了 useSession 钩子,用于客户端轻松访问会话数据。该钩子基于 nanostore 实现,支持所有主流框架和原生客户端,可确保会话状态变化(如登出)立即更新 UI。

user.tsx
import { authClient } from "@/lib/auth-client" // 导入认证客户端

export function User(){

    const { 
        data: session, 
        isPending, // 加载状态
        error, // 错误对象
        refetch // 重新获取会话
    } = authClient.useSession() 

    return (
        //...
    )
}
index.vue
<script setup lang="ts">
import { authClient } from "~/lib/auth-client"

const session = authClient.useSession() 
</script>

<template>
    <div>
        <div>
            <pre>{{ session.data }}</pre>
            <button v-if="session.data" @click="authClient.signOut()">
                登出
            </button>
        </div>
    </div>
</template>
user.svelte
<script lang="ts">
import { authClient } from "$lib/auth-client"; 

const session = authClient.useSession(); 
</script>
<p>
    {$session.data?.user.email}
</p>
auth-client.ts
import { authClient } from "~/lib/auth-client"; // 导入认证客户端

authClient.useSession.subscribe((value)=>{
    // 在这里处理会话数据 //
}) 
user.tsx
import { authClient } from "~/lib/auth-client"; 

export default function Home() {
    const session = authClient.useSession() 
    return (
        <pre>{JSON.stringify(session(), null, 2)}</pre>
    );
}

获取会话

如果不想使用钩子,也可以调用客户端的 getSession 方法。

user.tsx
import { authClient } from "@/lib/auth-client" // 导入认证客户端

const { data: session, error } = await authClient.getSession()

它也可与客户端数据获取库结合使用,比如 TanStack Query

服务器端

服务器端提供了一个 session 对象,用于访问会话数据。需要传入请求头对象给 getSession 方法。

示例:使用流行框架

server.ts
import { auth } from "./auth"; // 你的 Better Auth 服务器实例路径
import { headers } from "next/headers";

const session = await auth.api.getSession({
    headers: await headers() // 需传入请求头对象
})
route.ts
import { auth } from "lib/auth"; // 你的 Better Auth 服务器实例路径

export async function loader({ request }: LoaderFunctionArgs) {
    const session = await auth.api.getSession({
        headers: request.headers
    })

    return json({ session })
}
index.astro
---
import { auth } from "./auth";

const session = await auth.api.getSession({
    headers: Astro.request.headers,
});
---
<!-- 你的 Astro 模板 -->
+page.ts
import { auth } from "./auth";

export async function load({ request }) {
    const session = await auth.api.getSession({
        headers: request.headers
    })
    return {
        props: {
            session
        }
    }
}
index.ts
import { auth } from "./auth";

const app = new Hono();

app.get("/path", async (c) => {
    const session = await auth.api.getSession({
        headers: c.req.raw.headers
    })
});
server/session.ts
import { auth } from "~/utils/auth";

export default defineEventHandler((event) => {
    const session = await auth.api.getSession({
        headers: event.headers,
    })
});
app/routes/api/index.ts
import { auth } from "./auth";
import { createAPIFileRoute } from "@tanstack/start/api";

export const APIRoute = createAPIFileRoute("/api/$")({
    GET: async ({ request }) => {
        const session = await auth.api.getSession({
            headers: request.headers
        })
    },
});

更多详情请参见会话管理文档。

使用插件

Better Auth 的一大特色是拥有插件生态系统,能够通过少量代码实现复杂的认证功能。

下面示例演示如何使用两步验证插件添加双因素认证。

服务器配置

添加插件时,需要导入插件并将其传入 auth 实例的 plugins 选项。例如,添加双因素认证的代码如下:

auth.ts
import { betterAuth } from "better-auth"
import { twoFactor } from "better-auth/plugins"

export const auth = betterAuth({
    //...其他配置选项
    plugins: [ 
        twoFactor() 
    ] 
})

此时,服务器端会自动启用与双因素认证相关的路由和方法。

迁移数据库

添加插件后,需要为数据库添加相应表结构。你可以通过运行 migrate 命令完成,或者先使用 generate 命令生成 schema,再手动执行迁移。

生成 schema:

terminal
npx auth generate

执行迁移:

terminal
npx auth migrate

如果你希望手动添加 schema,可查看双因素插件文档里的数据库 schema 说明。

客户端配置

服务器端配置完成后,需要在客户端添加该插件。导入插件,并传入客户端 plugins 选项。例如:

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

const authClient = createAuthClient({
    plugins: [ 
        twoFactorClient({ 
            twoFactorPage: "/two-factor" // 如果用户需要验证二次认证时的跳转页面
        }) 
    ] 
})

此时,客户端会自动支持与双因素认证相关的方法。

profile.ts
import { authClient } from "./auth-client"

const enableTwoFactor = async() => {
    const data = await authClient.twoFactor.enable({
        password // 需要用户密码验证
    }) // 启用双因素认证
}

const disableTwoFactor = async() => {
    const data = await authClient.twoFactor.disable({
        password // 需要用户密码验证
    }) // 禁用双因素认证
}

const signInWith2Factor = async() => {
    const data = await authClient.signIn.email({
        //...
    })
    // 如果用户开启了双因素认证,会跳转到双因素验证页面
}

const verifyTOTP = async() => {
    const data = await authClient.twoFactor.verifyTOTP({
        code: "123456", // 用户输入的验证码 
        /**
         * 如果设备被信任,该设备上将不再需要二次认证
         */
        trustDevice: true
    })
}

下一步:查看 双因素认证插件文档