从 Auth.js 迁移到 Better Auth

介绍

【Introduction】

在本指南中,我们将介绍将项目从 Auth.js(前身为 NextAuth.js)迁移到 Better Auth 的步骤。由于这些项目的设计理念不同,迁移需要仔细规划和执行。如果你当前的设置运行良好,则无需紧急迁移。我们将继续处理 Auth.js 的安全补丁和关键问题。

【In this guide, we'll walk through the steps to migrate a project from Auth.js (formerly NextAuth.js) to Better Auth. Since these projects have different design philosophies, the migration requires careful planning and work. If your current setup is working well, there's no urgent need to migrate. We continue to handle security patches and critical issues for Auth.js.】

然而,如果你正在启动一个新项目或在现有设置中遇到挑战,我们强烈建议使用 Better Auth。我们的路线图包括之前仅限于 Auth.js 的功能,我们希望这能在不造成分裂的情况下更紧密地团结整个生态系统。

【However, if you're starting a new project or facing challenges with your current setup, we strongly recommend using Better Auth. Our roadmap includes features previously exclusive to Auth.js, and we hope this will unite the ecosystem more strongly without causing fragmentation.】

创建更好的认证实例

【Create Better Auth Instance】

在开始迁移过程之前,请在你的项目中设置 Better Auth。请按照安装指南开始操作。

【Before starting the migration process, set up Better Auth in your project. Follow the installation guide to get started.】

例如,如果你使用 GitHub OAuth 提供者,这里是 auth.ts 文件的一个比较。

【For example, if you use the GitHub OAuth provider, here is a comparison of the auth.ts file.】

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 核心架构的差异。

创建客户端实例

【Create Client Instance】

此客户端实例包含一组用于与 Better Auth 服务器实例交互的功能。更多信息,请参见这里

【This client instance includes a set of functions for interacting with the Better Auth server instance. For more information, see here.】

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

export const authClient = createAuthClient()

更新路由处理程序

【Update the Route Handler】

/app/api/auth/[...nextauth] 文件夹重命名为 /app/api/auth/[...all] 以避免混淆。然后,按如下方式更新 route.ts 文件:

【Rename the /app/api/auth/[...nextauth] folder to /app/api/auth/[...all] to avoid confusion. Then, update the route.ts file as follows:】

import { handlers } from "@/lib/auth"

export const { GET, POST } = handlers
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth)

会话管理

【Session Management】

在本节中,我们将探讨如何在 Better Auth 中管理会话,并与 Auth.js 进行比较。有关更多信息,请参见这里

【In this section, we'll look at how to manage sessions in Better Auth compared to Auth.js. For more information, see here.】

客户端

【Client-side】

登录

【Sign In】

以下是 Auth.js 和 Better Auth 在用户登录上的区别。例如,对于 GitHub OAuth 提供商:

【Here are the differences between Auth.js and Better Auth for signing in users. For example, with the GitHub OAuth provider:】

"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",
})

登出

【Sign Out】

以下是 Auth.js 与 Better Auth 在注销用户时的区别。

【Here are the differences between Auth.js and Better Auth when signing out users.】

"use client"

import { signOut } from "next-auth/react"

signOut()
"use client"

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

const { data, error } = await authClient.signOut()

获取会话

【Get Session】

以下是 Auth.js 与 Better Auth 在获取当前活动会话时的区别。

【Here are the differences between Auth.js and Better Auth for getting the current active session.】

"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()

服务器端

【Server-side】

登录

【Sign In】

以下是 Auth.js 和 Better Auth 在用户登录上的区别。例如,对于 GitHub OAuth 提供商:

【Here are the differences between Auth.js and Better Auth for signing in users. For example, with the GitHub OAuth provider:】

import { signIn } from "@/lib/auth"

await signIn("github")
import { auth } from "@/lib/auth";

const { redirect, url } = await auth.api.signInSocial({
  body: {
    provider: "github",
  },
})

登出

【Sign Out】

以下是 Auth.js 与 Better Auth 在注销用户时的区别。

【Here are the differences between Auth.js and Better Auth when signing out users.】

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(),
})

获取会话

【Get Session】

以下是 Auth.js 与 Better Auth 在获取当前活动会话时的区别。

【Here are the differences between Auth.js and Better Auth for getting the current active session.】

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(),
})

保护资源

【Protecting Resources】

代理(中间件)并不适用于慢速数据获取。虽然代理对于基于权限的重定向等乐观检查很有帮助,但它不应作为完整的会话管理或授权解决方案使用。 - Next.js 文档

Auth.js 提供了使用 Proxy(中间件)的方法,但我们建议在每个页面或路由上处理身份验证检查,而不是在 Proxy 或布局中进行。下面是使用 Better Auth 保护资源的基本示例。

【Auth.js offers approaches using Proxy (Middleware), but we recommend handling auth checks on each page or route rather than in a Proxy or Layout. Here is a basic example of protecting resources with Better Auth.】

app/dashboard/page.tsx
"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;
app/dashboard/page.tsx
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;

数据库模型

【Database models】

Auth.js 和 Better Auth 都提供无状态(JWT)和数据库会话策略。如果你在 Auth.js 中使用数据库会话策略,并计划在 Better Auth 中继续使用它,你还需要迁移你的数据库。

【Both Auth.js and Better Auth provide stateless (JWT) and database session strategies. If you were using the database session strategy in Auth.js and plan to continue using it in Better Auth, you will also need to migrate your database.】

就像 Auth.js 有数据库模型一样,Better Auth 也有一个核心架构。在本节中,我们将比较两者,并探讨它们之间的差异。

【Just like Auth.js has database models, Better Auth also has a core schema. In this section, we'll compare the two and explore the differences between them.】

用户 -> 用户

【User -> User】

Field NameTypeKeyDescription
idstringUnique identifier for each user
namestringUser's chosen display name
emailstringUser's email address for communication and login
emailVerifiedDateWhen the user's email was verified
imagestringUser's image url
Field NameTypeKeyDescription
idstringUnique identifier for each user
namestring-User's chosen display name
emailstring-User's email address for communication and login
emailVerifiedboolean-Whether the user's email is verified
imagestringUser's image url
createdAtDate-Timestamp of when the user account was created
updatedAtDate-Timestamp of the last update to the user's information

会话 -> 会话

【Session -> Session】

Field NameTypeKeyDescription
idstringUnique identifier for each session
userIdstringThe ID of the user
sessionTokenstring-The unique session token
expiresDate-The time when the session expires
Field NameTypeKeyDescription
idstringUnique identifier for each session
userIdstringThe ID of the user
tokenstring-The unique session token
expiresAtDate-The time when the session expires
ipAddressstringThe IP address of the device
userAgentstringThe user agent information of the device
createdAtDate-Timestamp of when the session was created
updatedAtDate-Timestamp of when the session was updated

账户 -> 账户

【Account -> Account】

Field NameTypeKeyDescription
idstringUnique identifier for each account
userIdstringThe ID of the user
typestring-Type of the account (e.g. 'oauth', 'email', 'credentials')
providerstring-Provider identifier
providerAccountIdstring-Account ID from the provider
refresh_tokenstringThe refresh token of the account. Returned by the provider
access_tokenstringThe access token of the account. Returned by the provider
expires_atnumberThe time when the access token expires
token_typestringType of the token
scopestringThe scope of the account. Returned by the provider
id_tokenstringThe ID token returned from the provider
session_statestringOAuth session state
Field NameTypeKeyDescription
idstringUnique identifier for each account
userIdstringThe ID of the user
accountIdstring-The ID of the account as provided by the SSO or equal to userId for credential accounts
providerIdstring-The ID of the provider
accessTokenstringThe access token of the account. Returned by the provider
refreshTokenstringThe refresh token of the account. Returned by the provider
accessTokenExpiresAtDateThe time when the access token expires
refreshTokenExpiresAtDateThe time when the refresh token expires
scopestringThe scope of the account. Returned by the provider
idTokenstringThe ID token returned from the provider
passwordstringThe password of the account. Mainly used for email and password authentication
createdAtDate-Timestamp of when the account was created
updatedAtDate-Timestamp of when the account was updated

验证令牌 -> 验证

【VerificationToken -> Verification】

Field NameTypeKeyDescription
identifierstringIdentifier for the verification request
tokenstringThe verification token
expiresDate-The time when the verification token expires
Field NameTypeKeyDescription
idstringUnique identifier for each verification
identifierstring-The identifier for the verification request
valuestring-The value to be verified
expiresAtDate-The time when the verification request expires
createdAtDate-Timestamp of when the verification request was created
updatedAtDate-Timestamp of when the verification request was updated

比较

【Comparison】

表格: 用户

  • 在 Better Auth 中,nameemailemailVerified 是必填项,而在 Auth.js 中是可选的
  • emailVerified 在 Better Auth 中使用布尔值,而在 Auth.js 中使用时间戳
  • Better Auth 包含 createdAtupdatedAt 时间戳

表格: 会话

  • Better Auth 使用 token 代替 sessionToken
  • Better Auth 使用 expiresAt 代替 expires
  • Better Auth 包含 ipAddressuserAgent 字段
  • Better Auth 包含 createdAtupdatedAt 时间戳

表格: 账户

  • Better Auth 使用 camelCase 命名(例如 refreshToken 而不是 refresh_token
  • Better Auth 包含 accountId 来区分账户 ID 和内部 ID
  • Better Auth 使用 providerId 而不是 provider
  • Better Auth 包含 accessTokenExpiresAtrefreshTokenExpiresAt 用于令牌管理
  • Better Auth 包含 password 字段以支持内置凭证认证
  • Better Auth 没有 type 字段,因为它由 providerId 决定
  • Better Auth 移除了 token_typesession_state 字段
  • Better Auth 包含 createdAtupdatedAt 时间戳

表: VerificationToken -> Verification

  • Better Auth 使用 Verification 表而不是 VerificationToken
  • Better Auth 使用单一的 id 主键而不是复合主键
  • Better Auth 使用 value 而不是 token 来支持各种验证类型
  • Better Auth 使用 expiresAt 而不是 expires
  • Better Auth 包含 createdAtupdatedAt 时间戳

如果你使用的是 Auth.js v4,请注意 v5 对数据库模式没有引入任何破坏性更改。如果你没有使用,可选字段如 oauth_token_secretoauth_token 可以删除。像 refresh_token_expires_in 这样很少使用的字段也可以删除。

自定义

【Customization】

你可能已经扩展了数据库模型或在 Auth.js 中实现了额外的逻辑。Better Auth 允许你以类型安全的方式自定义核心架构。你还可以在数据库操作的生命周期中定义自定义逻辑。欲了解更多详情,请参阅 概念 - 数据库

总结

【Wrapping Up】

现在你已经准备好从 Auth.js 迁移到 Better Auth 了。如需完整实现多种认证方法,请查看 Next.js 演示应用。Better Auth 提供更高的灵活性和更多功能,因此一定要浏览 文档 来充分发挥其潜力。

【Now you're ready to migrate from Auth.js to Better Auth. For a complete implementation with multiple authentication methods, check out the Next.js Demo App. Better Auth offers greater flexibility and more features, so be sure to explore the documentation to unlock its full potential.】

如果你在迁移过程中需要帮助,请加入我们的社区或联系 contact@better-auth.com

【If you need help with migration, join our community or reach out to contact@better-auth.com.】

On this page