从 Auth.js 迁移到 Better Auth
从 Auth.js 迁移到 Better Auth 的分步指南。
介绍
在本指南中,我们将逐步演示如何将项目从 Auth.js(前身为 NextAuth.js)迁移到 Better Auth。由于这两个项目的设计理念不同,迁移需要仔细规划和实施。如果您当前的设置运行良好,则无需紧急迁移。我们仍然会为 Auth.js 处理安全补丁和关键问题。
但如果您正在启动新项目或在当前设置中遇到挑战,我们强烈建议使用 Better Auth。我们的路线图包括以前仅 Auth.js 才有的功能,我们希望这能加强生态系统的统一,而不会导致分裂。
创建 Better Auth 实例
在开始迁移过程之前,在您的项目中设置 Better Auth。请按照安装指南开始。
例如,如果您使用 GitHub OAuth 提供程序,以下是 auth.ts 文件的对比。
import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [GitHub],
})import { betterAuth } from "better-auth";
export const auth = betterAuth({
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
},
},
})现在 Better Auth 支持无需任何数据库的无状态会话管理。如果您之前在 Auth.js 中使用了数据库适配器,可以参考下面的数据库模型以了解与 Better Auth 核心架构的差异。
创建客户端实例
此客户端实例包含一组用于与 Better Auth 服务端实例交互的函数。有关更多信息,请参阅客户端文档。
import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient()更新路由处理程序
将 /app/api/auth/[...nextauth] 文件夹重命名为 /app/api/auth/[...all],以避免混淆。然后,按如下方式更新 route.ts 文件:
import { handlers } from "@/lib/auth"
export const { GET, POST } = handlersimport { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { POST, GET } = toNextJsHandler(auth)会话管理
在本节中,我们将了解 Better Auth 与 Auth.js 相比如何管理会话。有关更多信息,请参阅会话管理文档。
客户端
登录
以下是在登录用户时,Auth.js 与 Better Auth 的区别。例如,使用 GitHub OAuth 提供程序:
"use client"
import { signIn } from "next-auth/react"
signIn("github")"use client"
import { authClient } from "@/lib/auth-client";
const { data, error } = await authClient.signIn.social({
provider: "github",
})登出
以下是在登出用户时,Auth.js 与 Better Auth 的区别。
"use client"
import { signOut } from "next-auth/react"
signOut()"use client"
import { authClient } from "@/lib/auth-client";
const { data, error } = await authClient.signOut()获取会话
以下是在获取当前活跃会话时,Auth.js 与 Better Auth 的区别。
"use client"
import { useSession } from "next-auth/react"
const { data, status, update } = useSession()"use client"
import { authClient } from "@/lib/auth-client";
const { data, error, refetch, isPending, isRefetching } = authClient.useSession()服务端
登录
以下是在登录用户时,Auth.js 与 Better Auth 的区别。例如,使用 GitHub OAuth 提供程序:
import { signIn } from "@/lib/auth"
await signIn("github")import { auth } from "@/lib/auth";
const { redirect, url } = await auth.api.signInSocial({
body: {
provider: "github",
},
})登出
以下是在登出用户时,Auth.js 与 Better Auth 的区别。
import { signOut } from "@/lib/auth"
await signOut()import { auth } from "@/lib/auth";
import { headers } from "next/headers";
const { success } = await auth.api.signOut({
headers: await headers(),
})获取会话
以下是在获取当前活跃会话时,Auth.js 与 Better Auth 的区别。
import { auth } from "@/lib/auth";
const session = await auth()import { auth } from "@/lib/auth";
import { headers } from "next/headers";
const session = await auth.api.getSession({
headers: await headers(),
})保护资源
代理(中间件)不适用于缓慢的数据获取。虽然代理对于基于权限的重定向等乐观检查可能很有用,但我们建议在每个页面或路由上处理身份验证检查,而不是在代理或布局中。以下是使用 Better Auth 保护资源的基本示例。
Auth.js 提供了使用代理(中间件)的方法,但我们建议在页面或路由本身上处理身份验证检查,而不是在代理或布局中。以下是使用 Better Auth 保护资源的基本示例。
"use client";
import { authClient } from "@/lib/auth-client";
import { redirect } from "next/navigation";
const DashboardPage = () => {
const { data, error, isPending } = authClient.useSession();
if (isPending) {
return <div>Pending</div>;
}
if (!data || error) {
redirect("/sign-in");
}
return (
<div>
<h1>Welcome {data.user.name}</h1>
</div>
);
};
export default DashboardPage;import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
const DashboardPage = async () => {
const session = await auth.api.getSession({
headers: await headers(),
});
if (!session) {
redirect("/sign-in");
}
return (
<div>
<h1>Welcome {session.user.name}</h1>
</div>
);
};
export default DashboardPage;数据库模型
Auth.js 和 Better Auth 都提供无状态(JWT)和数据库会话策略。如果您之前在 Auth.js 中使用了数据库会话策略并计划继续在 Better Auth 中使用它,您还需要迁移数据库。
就像 Auth.js 有数据库模型一样,Better Auth 也有核心架构。在本节中,我们将对两者进行比较并探索它们之间的差异。
用户 -> 用户
会话 -> 会话
账户 -> 账户
验证令牌 -> 验证
对比
表格: 用户
name、email和emailVerified在 Better Auth 中是必填项,而在 Auth.js 中是可选的- Better Auth 中
emailVerified使用布尔值,而 Auth.js 中使用时间戳 - Better Auth 包含
createdAt和updatedAt时间戳
表格: 会话
- Better Auth 使用
token而不是sessionToken - Better Auth 使用
expiresAt而不是expires - Better Auth 包含
ipAddress和userAgent字段 - Better Auth 包含
createdAt和updatedAt时间戳
表格: 账户
- Better Auth 使用驼峰命名法(例如
refreshToken而不是refresh_token) - Better Auth 包含
accountId以区分账户 ID 和内部 ID - Better Auth 使用
providerId而不是provider - Better Auth 包含
accessTokenExpiresAt和refreshTokenExpiresAt用于令牌管理 - Better Auth 包含
password字段以支持内置的凭证身份验证 - Better Auth 不包含
type字段,因为它由providerId决定 - Better Auth 移除了
token_type和session_state字段 - Better Auth 包含
createdAt和updatedAt时间戳
关于凭证迁移的关键提示:
在 Auth.js 中,密码通常直接存储在 User 模型中。在 Better Auth 中,密码必须存储在 Account 表中。
如果您要迁移带有密码的用户(包括用于电话号码插件),您必须为每个用户创建一个 account 表中的记录,并将 providerId 设置为 "credential"。没有此记录,基于密码的登录将失败。
表格: 验证令牌 -> 验证
- Better Auth 使用
Verification表代替VerificationToken - Better Auth 使用单一主键
id而不是复合主键 - Better Auth 使用
value而不是token以支持各种验证类型 - Better Auth 使用
expiresAt而不是expires - Better Auth 包含
createdAt和updatedAt时间戳
如果您使用的是 Auth.js v4,请注意 v5 并没有对数据库架构进行任何破坏性更改。可选字段(如 oauth_token_secret 和 oauth_token)如果未使用可以删除。不常用的字段(如 refresh_token_expires_in)也可以移除。
自定义
您可能已经扩展了 Auth.js 的数据库模型或实现了其他逻辑。Better Auth 允许您以类型安全的方式自定义核心架构。您还可以定义数据库操作的生命周期期间的自定义逻辑。更多详细信息,请参见概念 - 数据库。
Summary
You’re now ready to migrate from Auth.js to Better Auth. For a full implementation featuring multiple authentication methods, please refer to the Next.js demo app. Better Auth offers greater flexibility and more features, so be sure to explore the documentation to make the most of its full potential.
If you need help during the migration, please join our community or contact us at contact@better-auth.com.