配置BetterAuth认证Skill configuring-better-auth

这是一个关于使用Better Auth实现OAuth 2.1和OIDC认证的专业技能指南。它详细介绍了如何设置集中式单点登录(SSO)认证服务器,以及在Next.js应用中集成SSO客户端的完整流程。包含PKCE安全流程配置、JWKS令牌验证、MCP引导式设置等关键技术。适用于需要构建企业级身份认证系统的开发者,关键词包括:OAuth 2.1、OIDC、单点登录、SSO、Better Auth、Next.js认证、PKCE流程、JWKS验证、身份认证服务器。

身份认证 0 次安装 2 次浏览 更新于 3/2/2026

name: configuring-better-auth description: | 使用Better Auth和MCP辅助实现OAuth 2.1/OIDC认证。适用于设置集中式认证服务器(SSO提供商)、在Next.js应用中实现SSO客户端、配置PKCE流程或使用JWKS验证管理令牌。使用Better Auth MCP进行引导式设置。 不适用于没有OAuth/OIDC要求的简单会话认证。

Better Auth OAuth/OIDC

使用Better Auth实现集中式认证 - 可作为认证服务器或SSO客户端。

MCP服务器设置

Better Auth提供了一个由Chonkie驱动的MCP服务器,用于引导式配置:

claude mcp add --transport http better-auth https://mcp.chonkie.ai/better-auth/better-auth-builder/mcp

或在settings.json中:

{
  "mcpServers": {
    "better-auth": {
      "type": "http",
      "url": "https://mcp.chonkie.ai/better-auth/better-auth-builder/mcp"
    }
  }
}

何时使用MCP

任务 使用MCP?
初始Better Auth设置 是 - 引导式配置
添加OIDC提供商插件 是 - 生成正确配置
故障排除认证问题 是 - 可以分析设置
理解认证流程 是 - 解释概念
编写自定义中间件 否 - 使用以下模式

架构概述

┌─────────────────┐
│ Better Auth SSO │ ← 集中式认证服务器 (auth-server-setup.md)
│  (认证服务器)  │
└────────┬────────┘
         │
    ┌────┴────┐
    ▼         ▼
┌───────┐  ┌───────┐
│ 应用1 │  │ 应用2 │ ← SSO客户端 (sso-client-integration.md)
└───────┘  └───────┘

快速开始:认证服务器设置

npm install better-auth @better-auth/oidc-provider drizzle-orm

核心配置

// src/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { oidcProvider } from "better-auth/plugins/oidc-provider";

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "pg", schema }),
  emailAndPassword: { enabled: true },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7天
    updateAge: 60 * 60 * 24,     // 1天
  },
  plugins: [
    oidcProvider({
      loginPage: "/sign-in",
      consentPage: "/consent",
      // 公共客户端的PKCE(推荐)
      requirePKCE: true,
    }),
  ],
});

注册OAuth客户端

// 注册SSO客户端
await auth.api.createOAuthClient({
  name: "我的应用",
  redirectUris: ["http://localhost:3000/api/auth/callback"],
  type: "public", // 使用'public'进行PKCE
});

查看references/auth-server-setup.md获取包含JWKS、邮箱验证和管理面板的完整设置。


快速开始:SSO客户端集成

npm install jose

环境变量

NEXT_PUBLIC_SSO_URL=http://localhost:3001
NEXT_PUBLIC_SSO_CLIENT_ID=你的客户端ID

PKCE认证流程

// lib/auth-client.ts
import { generateCodeVerifier, generateCodeChallenge } from "./pkce";

export async function startLogin() {
  const verifier = generateCodeVerifier();
  const challenge = await generateCodeChallenge(verifier);

  // 将验证器存储在cookie中
  document.cookie = `pkce_verifier=${verifier}; path=/; SameSite=Lax`;

  const params = new URLSearchParams({
    client_id: process.env.NEXT_PUBLIC_SSO_CLIENT_ID!,
    redirect_uri: `${window.location.origin}/api/auth/callback`,
    response_type: "code",
    scope: "openid profile email",
    code_challenge: challenge,
    code_challenge_method: "S256",
  });

  window.location.href = `${SSO_URL}/oauth2/authorize?${params}`;
}

令牌交换(API路由)

// app/api/auth/callback/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const code = searchParams.get("code");
  const verifier = cookies().get("pkce_verifier")?.value;

  const response = await fetch(`${SSO_URL}/oauth2/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      client_id: process.env.NEXT_PUBLIC_SSO_CLIENT_ID!,
      code: code!,
      redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/api/auth/callback`,
      code_verifier: verifier!,
    }),
  });

  const tokens = await response.json();

  // 设置httpOnly cookies
  const res = NextResponse.redirect("/dashboard");
  res.cookies.set("access_token", tokens.access_token, { httpOnly: true });
  res.cookies.set("refresh_token", tokens.refresh_token, { httpOnly: true });
  return res;
}

查看references/sso-client-integration.md获取JWKS验证、令牌刷新和全局注销的完整实现。


PKCE工具函数

// lib/pkce.ts
export function generateCodeVerifier(): string {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64UrlEncode(array);
}

export async function generateCodeChallenge(verifier: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const hash = await crypto.subtle.digest("SHA-256", data);
  return base64UrlEncode(new Uint8Array(hash));
}

function base64UrlEncode(buffer: Uint8Array): string {
  return btoa(String.fromCharCode(...buffer))
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
}

关键模式

1. 令牌存储

  • 将令牌存储在httpOnly cookies中(而非localStorage)
  • 使用SameSite=Lax进行CSRF防护

2. 令牌刷新

async function refreshTokens() {
  const response = await fetch(`${SSO_URL}/oauth2/token`, {
    method: "POST",
    body: new URLSearchParams({
      grant_type: "refresh_token",
      client_id: process.env.NEXT_PUBLIC_SSO_CLIENT_ID!,
      refresh_token: currentRefreshToken,
    }),
  });
  return response.json();
}

3. JWKS验证

import { createRemoteJWKSet, jwtVerify } from "jose";

const JWKS = createRemoteJWKSet(
  new URL(`${SSO_URL}/.well-known/jwks.json`)
);

export async function verifyAccessToken(token: string) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer: SSO_URL,
    audience: process.env.NEXT_PUBLIC_SSO_CLIENT_ID,
  });
  return payload;
}

4. 全局注销

// 从所有应用注销
const logoutUrl = new URL(`${SSO_URL}/oauth2/logout`);
logoutUrl.searchParams.set("post_logout_redirect_uri", window.location.origin);
window.location.href = logoutUrl.toString();

常见问题

问题 解决方案
重定向后PKCE验证器丢失 在重定向前存储在httpOnly cookie中
令牌存储在localStorage 改用httpOnly cookies
JWKS获取失败 检查认证服务器的CORS设置
同意屏幕循环 确保同意页面保存决策

验证

运行:python3 scripts/verify.py

预期结果:✓ configuring-better-auth skill ready

如果验证失败

  1. 检查:references/文件夹包含两个设置文件
  2. 如果仍然失败,请停止并报告

参考资料