Better Auth 是一个全面的、开源的 TypeScript 认证框架。它设计为框架无关,但与 Next.js 集成良好,并提供了大量开箱即用的功能。
1. 替换 auth
包的依赖项
从 auth
包中卸载现有的 Clerk 依赖…
pnpm remove @clerk/nextjs @clerk/themes @clerk/types --filter @repo/auth
然后安装 Better Auth 依赖项:
pnpm add better-auth next --filter @repo/auth
此外,在 auth
软件包依赖关系中添加 @repo/database
。
2. 更新环境变量
使用以下命令生成密钥,并将其添加到每个 Next.js 应用(app
、web
和 api
)的 .env.local
文件中:
npx @better-auth/cli secret
这将在 .env.local
文件中添加一个 BETTER_AUTH_SECRET
环境变量。
3. 设置服务端和客户端认证
用以下代码更新 auth
包的文件:
import { betterAuth } from 'better-auth';
import { nextCookies } from "better-auth/next-js";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { database } from "@repo/database"
export const auth = betterAuth({
database: prismaAdapter(database, {
provider: 'postgresql',
}),
plugins: [
nextCookies()
// organization() // if you want to use organization plugin
],
//...add more options here
});
更多信息请参阅 Better Auth 安装指南。
4. 更新认证组件
更新 auth
包中的 sign-in.tsx
和 sign-up.tsx
组件,使用 client
文件中的 signIn
和 signUp
函数。
"use client";
import { signIn } from '../client';
import { useState } from 'react';
export const SignIn = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
return (
<form
onSubmit={async (e) => {
e.preventDefault();
await signIn.email({
email,
password,
})
}}
>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign in</button>
</form>
);
}
您可以使用不同的登录方式,如社交账号、手机号、用户名等。更多关于 Better Auth 基本用法的信息。
5. 生成 Prisma 模型
从根目录运行以下命令为 Better Auth 生成 Prisma 模型:
npx @better-auth/cli generate --output ./packages/database/prisma/schema.prisma --config ./packages/auth/server.ts
You may have to comment out the server-only
directive in packages/database/index.ts
temporarily. Ensure you have environment variables set.
6. 更新 Provider 文件
Better Auth 没有作为高阶组件的 Provider 概念,因此您可以完全删除它,或者像这样替换为一个存根:
packages/auth/provider.tsx
import type { ReactNode } from 'react';
type AuthProviderProps = {
children: ReactNode;
};
export const AuthProvider = ({ children }: AuthProviderProps) => children;
7. 更改中间件
将 auth
包中的中间件更改为以下内容:
packages/auth/middleware.ts
import type { NextRequest } from "next/server";
import { NextResponse } from 'next/server';
const isProtectedRoute = (request: NextRequest) => {
return request.url.startsWith("/dashboard"); // change this to your protected route
}
export const authMiddleware = async (request: NextRequest) => {
const url = new URL('/api/auth/get-session', request.nextUrl.origin);
const response = await fetch(url, {
headers: {
cookie: request.headers.get('cookie') || '',
},
});
const session = await response.json();
if (isProtectedRoute(request) && !session) {
return NextResponse.redirect(new URL("/sign-in", request.url));
}
return NextResponse.next();
}
8. 更新您的应用
从这里开始,您需要用 Better Auth 替换应用中剩余的 Clerk 实现。
Here is some inspiration:
const user = await currentUser();
const { redirectToSignIn } = await auth();
// to
const session = await auth.api.getSession({
headers: await headers(), // from next/headers
});
if (!session?.user) {
return redirect('/sign-in'); // from next/navigation
}
// do something with session.user
const { orgId } = await auth();
// to
const h = await headers(); // from next/headers
const session = await auth.api.getSession({
headers: h,
});
const orgId = session?.session.activeOrganizationId;
const fullOrganization = await auth.api.getFullOrganization({
headers: h,
query: { organizationId: orgId },
});
import { clerkClient } from '@repo/auth/server';
const clerk = await clerkClient();
const users = await clerk.users.getUserList();
const user = users.data.find(
(user) => user.privateMetadata.stripeCustomerId === customerId
);
// to
import { database } from '@repo/database';
const user = await database.user.findFirst({
where: {
privateMetadata: {
contains: { stripeCustomerId: customerId },
},
},
});
关于组织功能的使用,请查看组织插件和更多Better Auth 文档。