better-auth
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBetter Auth Integration Guide
Better Auth集成指南
Overview
概述
Better Auth is a comprehensive authentication framework for TypeScript that provides type-safe authentication with support for multiple providers, 2FA, SSO, organizations, and more. This skill covers complete integration patterns for NestJS backend with Drizzle ORM and PostgreSQL, plus Next.js App Router frontend integration.
Better Auth是一款面向TypeScript的全功能认证框架,提供类型安全的认证能力,支持多登录提供商、2FA、SSO、组织管理等功能。本指南涵盖NestJS后端结合Drizzle ORM与PostgreSQL的完整集成方案,以及Next.js App Router前端的集成方法。
When to Use
适用场景
- Setting up Better Auth with NestJS backend
- Integrating Next.js App Router frontend with Better Auth
- Configuring Drizzle ORM schema with PostgreSQL for authentication
- Implementing social login (GitHub, Google, Facebook, Microsoft, etc.)
- Adding Multi-Factor Authentication (MFA/2FA) with TOTP
- Implementing passkey (WebAuthn) passwordless authentication
- Managing trusted devices for streamlined authentication
- Using backup codes for 2FA account recovery
- Adding authentication plugins (2FA, Organization, SSO, Magic Link, Passkey)
- Email/password authentication with secure session management
- Creating protected routes and authentication middleware
- Implementing role-based access control (RBAC)
- Building multi-tenant applications with organizations
- 在NestJS后端中搭建Better Auth
- 为Next.js App Router前端集成Better Auth
- 配置基于PostgreSQL的Drizzle ORM认证schema
- 实现社交登录(GitHub、Google、Facebook、Microsoft等)
- 添加多因素认证(MFA/2FA)与TOTP支持
- 实现密钥登录(WebAuthn)无密码认证
- 管理可信设备以简化认证流程
- 使用备份码进行2FA账号恢复
- 添加认证插件(2FA、组织管理、SSO、魔法链接、密钥登录)
- 带安全会话管理的邮箱/密码认证
- 创建受保护路由与认证中间件
- 实现基于角色的访问控制(RBAC)
- 构建支持组织的多租户应用
Quick Start
快速开始
Installation
安装
bash
undefinedbash
undefinedBackend (NestJS)
后端(NestJS)
npm install better-auth @auth/drizzle-adapter
npm install drizzle-orm pg
npm install -D drizzle-kit
npm install better-auth @auth/drizzle-adapter
npm install drizzle-orm pg
npm install -D drizzle-kit
Frontend (Next.js)
前端(Next.js)
npm install better-auth
undefinednpm install better-auth
undefinedBasic Setup
基础配置
- Configure Better Auth instance (backend)
- Set up Drizzle schema with Better Auth tables
- Create auth module in NestJS
- Configure Next.js auth client
- Set up middleware for protected routes
See References/ for detailed setup instructions.
- 配置Better Auth实例(后端)
- 使用Better Auth表设置Drizzle schema
- 在NestJS中创建认证模块
- 配置Next.js认证客户端
- 为受保护路由设置中间件
详细配置说明请查看References/目录。
Architecture
架构
Backend (NestJS)
后端(NestJS)
src/
├── auth/
│ ├── auth.module.ts # Auth module configuration
│ ├── auth.controller.ts # Auth HTTP endpoints
│ ├── auth.service.ts # Business logic
│ ├── auth.guard.ts # Route protection
│ └── schema.ts # Drizzle auth schema
├── database/
│ ├── database.module.ts # Database module
│ └── database.service.ts # Drizzle connection
└── main.tssrc/
├── auth/
│ ├── auth.module.ts # 认证模块配置
│ ├── auth.controller.ts # 认证HTTP端点
│ ├── auth.service.ts # 业务逻辑
│ ├── auth.guard.ts # 路由保护
│ └── schema.ts # Drizzle认证schema
├── database/
│ ├── database.module.ts # 数据库模块
│ └── database.service.ts # Drizzle连接
└── main.tsFrontend (Next.js)
前端(Next.js)
app/
├── (auth)/
│ ├── sign-in/
│ │ └── page.tsx # Sign in page
│ └── sign-up/
│ └── page.tsx # Sign up page
├── (dashboard)/
│ ├── dashboard/
│ │ └── page.tsx # Protected page
│ └── layout.tsx # With auth check
├── api/
│ └── auth/
│ └── [...auth]/route.ts # Auth API route
├── layout.tsx # Root layout
└── middleware.ts # Auth middleware
lib/
├── auth.ts # Better Auth client
└── utils.tsapp/
├── (auth)/
│ ├── sign-in/
│ │ └── page.tsx # 登录页面
│ └── sign-up/
│ └── page.tsx # 注册页面
├── (dashboard)/
│ ├── dashboard/
│ │ └── page.tsx # 受保护页面
│ └── layout.tsx # 带认证检查的布局
├── api/
│ └── auth/
│ └── [...auth]/route.ts # 认证API路由
├── layout.tsx # 根布局
└── middleware.ts # 认证中间件
lib/
├── auth.ts # Better Auth客户端
└── utils.tsInstructions
操作步骤
Phase 1: Database Setup
阶段1:数据库配置
-
Install Dependenciesbash
npm install drizzle-orm pg @auth/drizzle-adapter better-auth npm install -D drizzle-kit -
Configure Drizzle
- Create
drizzle.config.ts - Set up database connection
- Define schema with Better Auth tables
- Create
-
Generate and Run Migrationsbash
npx drizzle-kit generate npx drizzle-kit migrate
-
安装依赖bash
npm install drizzle-orm pg @auth/drizzle-adapter better-auth npm install -D drizzle-kit -
配置Drizzle
- 创建
drizzle.config.ts - 设置数据库连接
- 定义包含Better Auth表的schema
- 创建
-
生成并运行迁移bash
npx drizzle-kit generate npx drizzle-kit migrate
Phase 2: Backend Setup (NestJS)
阶段2:后端配置(NestJS)
-
Create Database Module
- Set up Drizzle connection
- Provide database service
-
Configure Better Auth
- Create auth instance with Drizzle adapter
- Configure providers (GitHub, Google, etc.)
- Set up session management
-
Create Auth Module
- Auth controller with endpoints
- Auth service with business logic
- Auth guard for protection
-
创建数据库模块
- 设置Drizzle连接
- 提供数据库服务
-
配置Better Auth
- 使用Drizzle适配器创建认证实例
- 配置登录提供商(GitHub、Google等)
- 设置会话管理
-
创建认证模块
- 带端点的认证控制器
- 带业务逻辑的认证服务
- 用于保护路由的认证守卫
Phase 3: Frontend Setup (Next.js)
阶段3:前端配置(Next.js)
-
Configure Auth Client
- Set up Better Auth client
- Configure server actions
-
Create Auth Pages
- Sign in page
- Sign up page
- Error handling
-
Add Middleware
- Protect routes
- Handle redirects
-
配置认证客户端
- 设置Better Auth客户端
- 配置服务器操作
-
创建认证页面
- 登录页面
- 注册页面
- 错误处理
-
添加中间件
- 保护路由
- 处理重定向
Phase 4: Advanced Features
阶段4:高级功能
-
Social Providers
- Configure OAuth apps
- Add provider callbacks
-
Plugins
- Two-Factor Authentication (2FA)
- Organizations
- SSO
- Magic Links
- Passkeys
-
社交登录提供商
- 配置OAuth应用
- 添加提供商回调
-
插件
- 双因素认证(2FA)
- 组织管理
- SSO
- 魔法链接
- 密钥登录
Examples
示例
Example 1: Complete NestJS Auth Setup
示例1:完整NestJS认证配置
Input: Developer needs to set up Better Auth in a new NestJS project with PostgreSQL.
Process:
typescript
// 1. Create auth instance
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: { ...schema }
}),
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}
}
});
// 2. Create auth controller
@Controller('auth')
export class AuthController {
@All('*')
async handleAuth(@Req() req: Request, @Res() res: Response) {
return auth.handler(req);
}
}Output: Fully functional auth endpoints at with GitHub OAuth support.
/auth/*需求:开发者需要在新的NestJS项目中结合PostgreSQL搭建Better Auth。
实现流程:
typescript
// 1. 创建认证实例
export const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "pg",
schema: { ...schema }
}),
socialProviders: {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}
}
});
// 2. 创建认证控制器
@Controller('auth')
export class AuthController {
@All('*')
async handleAuth(@Req() req: Request, @Res() res: Response) {
return auth.handler(req);
}
}结果:在路径下生成带GitHub OAuth支持的完整功能认证端点。
/auth/*Example 2: Next.js Middleware for Route Protection
示例2:Next.js路由保护中间件
Input: Protect dashboard routes in Next.js App Router.
Process:
typescript
// middleware.ts
import { auth } from '@/lib/auth';
export default auth((req) => {
if (!req.auth && req.nextUrl.pathname.startsWith('/dashboard')) {
const newUrl = new URL('/sign-in', req.nextUrl.origin);
return Response.redirect(newUrl);
}
});
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*']
};Output: Unauthenticated users are redirected to when accessing .
/sign-in/dashboard/*需求:在Next.js App Router中保护仪表盘路由。
实现流程:
typescript
// middleware.ts
import { auth } from '@/lib/auth';
export default auth((req) => {
if (!req.auth && req.nextUrl.pathname.startsWith('/dashboard')) {
const newUrl = new URL('/sign-in', req.nextUrl.origin);
return Response.redirect(newUrl);
}
});
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*']
};结果:未认证用户访问时会被重定向到页面。
/dashboard/*/sign-inExample 3: Server Component with Session
示例3:带会话的Next.js服务器组件
Input: Display user data in a Next.js Server Component.
Process:
typescript
// app/dashboard/page.tsx
import { auth } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await auth();
if (!session) {
redirect('/sign-in');
}
return (
<div>
<h1>Welcome, {session.user.name}</h1>
<p>Email: {session.user.email}</p>
</div>
);
}Output: Renders user information only for authenticated users, redirects others to sign-in.
需求:在Next.js服务器组件中显示用户数据。
实现流程:
typescript
// app/dashboard/page.tsx
import { auth } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await auth();
if (!session) {
redirect('/sign-in');
}
return (
<div>
<h1>欢迎,{session.user.name}</h1>
<p>邮箱:{session.user.email}</p>
</div>
);
}结果:仅为已认证用户渲染用户信息,未认证用户会被重定向到登录页面。
Example 4: Adding Two-Factor Authentication
示例4:添加双因素认证
Input: Enable 2FA for enhanced account security.
Process:
typescript
// Enable 2FA plugin
export const auth = betterAuth({
plugins: [
twoFactor({
issuer: 'MyApp',
otpOptions: {
digits: 6,
period: 30
}
})
]
});
// Client-side enable 2FA
const { data, error } = await authClient.twoFactor.enable({
password: 'user-password'
});Output: Users can enable TOTP-based 2FA and verify with authenticator apps.
需求:启用2FA以增强账号安全性。
实现流程:
typescript
// 启用2FA插件
export const auth = betterAuth({
plugins: [
twoFactor({
issuer: 'MyApp',
otpOptions: {
digits: 6,
period: 30
}
})
]
});
// 客户端启用2FA
const { data, error } = await authClient.twoFactor.enable({
password: 'user-password'
});结果:用户可启用基于TOTP的2FA,并使用认证器应用进行验证。
Example 5: TOTP Verification with Trusted Device
示例5:带可信设备的TOTP验证
Input: User has enabled 2FA and wants to sign in, marking the device as trusted.
Process:
typescript
// Server-side: Configure 2FA with OTP sending
export const auth = betterAuth({
plugins: [
twoFactor({
issuer: 'MyApp',
otpOptions: {
async sendOTP({ user, otp }, ctx) {
// Send OTP via email, SMS, or other method
await sendEmail({
to: user.email,
subject: 'Your verification code',
body: `Code: ${otp}`
});
}
}
})
]
});
// Client-side: Verify TOTP and trust device
const verify2FA = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyTotp({
code,
trustDevice: true // Device trusted for 30 days
});
if (data) {
// Redirect to dashboard
router.push('/dashboard');
}
};Output: User is authenticated, device is trusted for 30 days (no 2FA prompt on next sign-ins).
需求:用户已启用2FA,登录时将设备标记为可信设备。
实现流程:
typescript
// 服务器端:配置带OTP发送的2FA
export const auth = betterAuth({
plugins: [
twoFactor({
issuer: 'MyApp',
otpOptions: {
async sendOTP({ user, otp }, ctx) {
// 通过邮箱、短信或其他方式发送OTP
await sendEmail({
to: user.email,
subject: '您的验证码',
body: `验证码:${otp}`
});
}
}
})
]
});
// 客户端:验证TOTP并信任设备
const verify2FA = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyTotp({
code,
trustDevice: true // 设备将被信任30天
});
if (data) {
// 重定向到仪表盘
router.push('/dashboard');
}
};结果:用户完成认证,设备被信任30天(下次登录无需2FA验证)。
Example 6: Passkey Authentication Setup
示例6:密钥登录(Passkey)配置
Input: Enable passkey (WebAuthn) authentication for passwordless login.
Process:
typescript
// Server-side: Configure passkey plugin
import { passkey } from '@better-auth/passkey';
export const auth = betterAuth({
plugins: [
passkey({
rpID: 'example.com', // Relying Party ID (your domain)
rpName: 'My App', // Display name
advanced: {
webAuthnChallengeCookie: 'my-app-passkey'
}
})
]
});
// Client-side: Register passkey
const registerPasskey = async () => {
const { data, error } = await authClient.passkey.register({
name: 'My Device'
});
if (data) {
console.log('Passkey registered successfully');
}
};
// Client-side: Sign in with passkey
const signInWithPasskey = async () => {
await authClient.signIn.passkey({
autoFill: true, // Enable conditional UI
fetchOptions: {
onSuccess() {
router.push('/dashboard');
}
}
});
};Output: Users can register and authenticate with passkeys (biometric, PIN, or security key).
需求:启用密钥登录(WebAuthn)实现无密码登录。
实现流程:
typescript
// 服务器端:配置密钥登录插件
import { passkey } from '@better-auth/passkey';
export const auth = betterAuth({
plugins: [
passkey({
rpID: 'example.com', // 依赖方ID(你的域名)
rpName: 'My App', // 显示名称
advanced: {
webAuthnChallengeCookie: 'my-app-passkey'
}
})
]
});
// 客户端:注册密钥
const registerPasskey = async () => {
const { data, error } = await authClient.passkey.register({
name: 'My Device'
});
if (data) {
console.log('密钥注册成功');
}
};
// 客户端:使用密钥登录
const signInWithPasskey = async () => {
await authClient.signIn.passkey({
autoFill: true, // 启用条件UI
fetchOptions: {
onSuccess() {
router.push('/dashboard');
}
}
});
};结果:用户可注册并使用密钥(生物识别、PIN或安全密钥)进行认证。
Example 7: Passkey Conditional UI (Autofill)
示例7:密钥登录条件UI(自动填充)
Input: Implement passkey autofill in sign-in form for seamless authentication.
Process:
tsx
// Component with conditional UI support
'use client';
import { useEffect } from 'react';
import { authClient } from '@/lib/auth/client';
export default function SignInPage() {
useEffect(() => {
// Check for conditional mediation support
if (!PublicKeyCredential.isConditionalMediationAvailable ||
!PublicKeyCredential.isConditionalMediationAvailable()) {
return;
}
// Enable passkey autofill
void authClient.signIn.passkey({ autoFill: true });
}, []);
return (
<form>
<label htmlFor="email">Email:</label>
<input
type="email"
name="email"
autoComplete="username webauthn"
/>
<label htmlFor="password">Password:</label>
<input
type="password"
name="password"
autoComplete="current-password webauthn"
/>
<button type="submit">Sign In</button>
</form>
);
}Output: Browser automatically suggests passkeys when user focuses on input fields.
需求:在登录表单中实现密钥自动填充以简化认证流程。
实现流程:
tsx
// 支持条件UI的组件
'use client';
import { useEffect } from 'react';
import { authClient } from '@/lib/auth/client';
export default function SignInPage() {
useEffect(() => {
// 检查是否支持条件中介
if (!PublicKeyCredential.isConditionalMediationAvailable ||
!PublicKeyCredential.isConditionalMediationAvailable()) {
return;
}
// 启用密钥自动填充
void authClient.signIn.passkey({ autoFill: true });
}, []);
return (
<form>
<label htmlFor="email">邮箱:</label>
<input
type="email"
name="email"
autoComplete="username webauthn"
/>
<label htmlFor="password">密码:</label>
<input
type="password"
name="password"
autoComplete="current-password webauthn"
/>
<button type="submit">登录</button>
</form>
);
}结果:当用户聚焦输入框时,浏览器会自动提示可用的密钥。
Example 8: Backup Codes for 2FA Recovery
示例8:2FA恢复用备份码
Input: User needs backup codes to recover account if authenticator app is lost.
Process:
typescript
// Enable 2FA - backup codes are generated automatically
const enable2FA = async (password: string) => {
const { data, error } = await authClient.twoFactor.enable({
password
});
if (data) {
// IMPORTANT: Display backup codes to user immediately
console.log('Backup codes (save these securely):');
data.backupCodes.forEach((code: string) => {
console.log(code);
});
// Show TOTP URI as QR code
const qrCodeUrl = data.totpURI;
displayQRCode(qrCodeUrl);
}
};
// Recover with backup code
const recoverWithBackupCode = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyBackupCode({
code
});
if (data) {
// Allow user to disable 2FA or set up new authenticator
router.push('/settings/2fa');
}
};Output: User receives single-use backup codes for account recovery.
需求:用户需要备份码,以便在丢失认证器应用时恢复账号。
实现流程:
typescript
// 启用2FA - 自动生成备份码
const enable2FA = async (password: string) => {
const { data, error } = await authClient.twoFactor.enable({
password
});
if (data) {
// 重要:立即向用户显示备份码
console.log('备份码(请妥善保存):');
data.backupCodes.forEach((code: string) => {
console.log(code);
});
// 将TOTP URI显示为二维码
const qrCodeUrl = data.totpURI;
displayQRCode(qrCodeUrl);
}
};
// 使用备份码恢复账号
const recoverWithBackupCode = async (code: string) => {
const { data, error } = await authClient.twoFactor.verifyBackupCode({
code
});
if (data) {
// 允许用户禁用2FA或设置新的认证器
router.push('/settings/2fa');
}
};结果:用户获取一次性备份码用于账号恢复。
Common Patterns
常见模式
Protected Route Pattern
受保护路由模式
typescript
// NestJS Guard
@Controller('dashboard')
@UseGuards(AuthGuard)
export class DashboardController {
@Get()
getDashboard(@Request() req) {
return req.user;
}
}typescript
// Next.js Server Component
import { auth } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function Dashboard() {
const session = await auth();
if (!session) {
redirect('/sign-in');
}
return <div>Welcome {session.user.name}</div>;
}typescript
// NestJS守卫
@Controller('dashboard')
@UseGuards(AuthGuard)
export class DashboardController {
@Get()
getDashboard(@Request() req) {
return req.user;
}
}typescript
// Next.js服务器组件
import { auth } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function Dashboard() {
const session = await auth();
if (!session) {
redirect('/sign-in');
}
return <div>欢迎 {session.user.name}</div>;
}Session Management Pattern
会话管理模式
typescript
// Get session in API route
const session = await auth.api.getSession({
headers: await headers()
});
// Get session in Server Component
const session = await auth();
// Get session in Client Component
'use client';
import { useSession } from '@/lib/auth/client';
const { data: session } = useSession();typescript
// 在API路由中获取会话
const session = await auth.api.getSession({
headers: await headers()
});
// 在服务器组件中获取会话
const session = await auth();
// 在客户端组件中获取会话
'use client';
import { useSession } from '@/lib/auth/client';
const { data: session } = useSession();Best Practices
最佳实践
-
Environment Variables: Always use environment variables for sensitive data (secrets, database URLs, OAuth credentials)
-
Secret Generation: Use strong, unique secrets for Better Auth. Generate with
openssl rand -base64 32 -
HTTPS Required: OAuth callbacks require HTTPS in production. Useor similar for local testing
ngrok -
Session Security: Configure appropriate session expiration times based on your security requirements
-
Database Indexing: Add indexes on frequently queried fields (email, userId) for performance
-
Error Handling: Implement proper error handling for auth failures without revealing sensitive information
-
Rate Limiting: Add rate limiting to auth endpoints to prevent brute force attacks
-
CSRF Protection: Better Auth includes CSRF protection. Always use the provided methods for state changes
-
Type Safety: Leverage TypeScript types from Better Auth for full type safety across frontend and backend
-
Testing: Test auth flows thoroughly including success cases, error cases, and edge conditions
-
环境变量:始终使用环境变量存储敏感数据(密钥、数据库URL、OAuth凭证)
-
密钥生成:为Better Auth使用强唯一密钥,可通过生成
openssl rand -base64 32 -
HTTPS要求:生产环境中OAuth回调需要HTTPS,本地测试可使用等工具
ngrok -
会话安全:根据安全需求配置合适的会话过期时间
-
数据库索引:为频繁查询的字段(邮箱、userId)添加索引以提升性能
-
错误处理:为认证失败实现适当的错误处理,避免泄露敏感信息
-
速率限制:为认证端点添加速率限制以防止暴力破解攻击
-
CSRF保护:Better Auth内置CSRF保护,状态变更时请始终使用提供的方法
-
类型安全:利用Better Auth提供的TypeScript类型,在前后端实现完整的类型安全
-
测试:全面测试认证流程,包括成功场景、错误场景和边缘情况
Constraints and Warnings
约束与警告
Security Notes
安全注意事项
- Never commit secrets: Add to
.envand never commit OAuth secrets or database credentials.gitignore - Validate redirect URLs: Always validate OAuth redirect URLs to prevent open redirects
- Hash passwords: Better Auth handles password hashing automatically. Never implement your own
- Session storage: For production, use Redis or another scalable session store
- HTTPS Only: Always use HTTPS for authentication in production
- OAuth Secrets: Keep OAuth client secrets secure. Rotate them periodically
- Email Verification: Always implement email verification for password-based auth
- 切勿提交密钥:将添加到
.env中,绝不要提交OAuth密钥或数据库凭证.gitignore - 验证重定向URL:始终验证OAuth重定向URL以防止开放重定向攻击
- 密码哈希:Better Auth会自动处理密码哈希,切勿自行实现
- 会话存储:生产环境中请使用Redis或其他可扩展的会话存储
- 仅使用HTTPS:生产环境中认证必须使用HTTPS
- OAuth密钥安全:妥善保管OAuth客户端密钥,并定期轮换
- 邮箱验证:基于密码的认证务必实现邮箱验证
Known Limitations
已知限制
- Better Auth requires Node.js 18+ for Next.js App Router support
- Some OAuth providers require specific redirect URL formats
- Passkeys require HTTPS and compatible browsers
- Organization features require additional database tables
- Better Auth需要Node.js 18+以支持Next.js App Router
- 部分OAuth提供商要求特定的重定向URL格式
- 密钥登录需要HTTPS和兼容的浏览器
- 组织功能需要额外的数据库表
Version Requirements
版本要求
Backend Dependencies
后端依赖
json
{
"dependencies": {
"better-auth": "^1.2.0",
"@auth/drizzle-adapter": "^1.0.0",
"drizzle-orm": "^0.35.0",
"pg": "^8.12.0",
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/config": "^3.0.0"
},
"devDependencies": {
"drizzle-kit": "^0.24.0",
"@types/pg": "^8.11.0"
}
}json
{
"dependencies": {
"better-auth": "^1.2.0",
"@auth/drizzle-adapter": "^1.0.0",
"drizzle-orm": "^0.35.0",
"pg": "^8.12.0",
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/config": "^3.0.0"
},
"devDependencies": {
"drizzle-kit": "^0.24.0",
"@types/pg": "^8.11.0"
}
}Frontend Dependencies
前端依赖
json
{
"dependencies": {
"better-auth": "^1.2.0",
"next": "^15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
}
}json
{
"dependencies": {
"better-auth": "^1.2.0",
"next": "^15.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
}
}Database
数据库
- PostgreSQL 14+ recommended
- For local development: Docker PostgreSQL or Postgres.app
- 推荐使用PostgreSQL 14+
- 本地开发可使用Docker PostgreSQL或Postgres.app
Troubleshooting
故障排除
1. "Session not found" errors
1. "会话未找到"错误
Problem: Session data is not being persisted or retrieved correctly.
Solution:
- Verify database connection is working
- Check session table exists and has data
- Ensure is set consistently
BETTER_AUTH_SECRET - Verify cookie domain settings match your application domain
问题:会话数据未正确持久化或获取。
解决方案:
- 验证数据库连接正常
- 检查会话表是否存在且有数据
- 确保在所有环境中一致
BETTER_AUTH_SECRET - 验证Cookie域名设置与应用域名匹配
2. OAuth callback fails with "Invalid state"
2. OAuth回调返回"无效状态"
Problem: OAuth state mismatch during callback.
Solution:
- Clear cookies and try again
- Ensure is set correctly in environment
BETTER_AUTH_URL - Check that redirect URI in OAuth app matches exactly
- Verify no reverse proxy is modifying callbacks
问题:OAuth回调过程中状态不匹配。
解决方案:
- 清除Cookie后重试
- 确保环境变量中设置正确
BETTER_AUTH_URL - 检查OAuth应用中的重定向URI是否完全匹配
- 验证反向代理未修改回调请求
3. TypeScript type errors with auth()
3. auth()函数出现TypeScript类型错误
Problem: Type inference not working correctly.
Solution:
- Ensure TypeScript 5+ is installed
- Use to generate types
npx better-auth typegen - Restart TypeScript server in your IDE
- Check that versions match on frontend and backend
better-auth
问题:类型推断未正常工作。
解决方案:
- 确保安装了TypeScript 5+
- 使用生成类型
npx better-auth typegen - 重启IDE中的TypeScript服务器
- 检查前后端版本是否一致
better-auth
4. Migration fails with "table already exists"
4. 迁移时出现"表已存在"错误
Problem: Drizzle migration conflicts.
Solution:
- Drop existing tables and re-run migration
- Or use for development
drizzle-kit push - For production, write manual migration to handle existing tables
问题:Drizzle迁移冲突。
解决方案:
- 删除现有表后重新运行迁移
- 开发环境中使用
drizzle-kit push - 生产环境中编写手动迁移以处理现有表
5. CORS errors from frontend to backend
5. 前端到后端出现CORS错误
Problem: Frontend cannot communicate with backend auth endpoints.
Solution:
- Configure CORS in NestJS backend
- Add frontend origin to allowed origins
- Ensure credentials are included:
credentials: 'include'
问题:前端无法与后端认证端点通信。
解决方案:
- 在NestJS后端配置CORS
- 将前端源添加到允许的源列表中
- 确保包含凭证:
credentials: 'include'
6. Social provider returns "redirect_uri_mismatch"
6. 社交提供商返回"redirect_uri_mismatch"
Problem: OAuth app configuration mismatch.
Solution:
- Update OAuth app with exact callback URL
- Include both http://localhost and production URLs
- For ngrok/local testing, update OAuth app each time URL changes
问题:OAuth应用配置不匹配。
解决方案:
- 更新OAuth应用中的回调URL为精确值
- 同时添加http://localhost和生产环境URL
- 使用ngrok/本地测试时,每次URL变更都需更新OAuth应用
Resources
资源
Documentation
文档
Reference Implementations
参考实现
- See for complete NestJS setup
references/nestjs-setup.md - See for complete Next.js setup
references/nextjs-setup.md - See for plugin configuration
references/plugins.md - See for example code files
assets/
- 查看获取完整NestJS配置
references/nestjs-setup.md - 查看获取完整Next.js配置
references/nextjs-setup.md - 查看获取插件配置
references/plugins.md - 查看目录获取示例代码文件
assets/
Environment Variables
环境变量
See for all required environment variables.
Assets/env.example查看获取所有必填环境变量。
Assets/env.exampleEnvironment Variables
环境变量
bash
undefinedbash
undefinedDatabase
数据库
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
Better Auth
Better Auth
BETTER_AUTH_SECRET=your-secret-key-min-32-chars
BETTER_AUTH_URL=http://localhost:3000
BETTER_AUTH_SECRET=your-secret-key-min-32-chars
BETTER_AUTH_URL=http://localhost:3000
OAuth Providers
OAuth提供商
AUTH_GITHUB_CLIENT_ID=your-github-client-id
AUTH_GITHUB_CLIENT_SECRET=your-github-client-secret
AUTH_GOOGLE_CLIENT_ID=your-google-client-id
AUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret
AUTH_GITHUB_CLIENT_ID=your-github-client-id
AUTH_GITHUB_CLIENT_SECRET=your-github-client-secret
AUTH_GOOGLE_CLIENT_ID=your-google-client-id
AUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret
Email (for magic links and verification)
邮箱(用于魔法链接和验证)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-smtp-user
SMTP_PASSWORD=your-smtp-password
SMTP_FROM=noreply@example.com
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-smtp-user
SMTP_PASSWORD=your-smtp-password
SMTP_FROM=noreply@example.com
Session (optional, for Redis)
会话(可选,用于Redis)
REDIS_URL=redis://localhost:6379
undefinedREDIS_URL=redis://localhost:6379
undefined