Guides

认证

Nebutra 端到端认证处理——提供商设置、令牌验证和会话管理。

认证提供商

Nebutra 通过 @nebutra/auth 支持可切换认证提供商。请保持 AUTH_PROVIDERNEXT_PUBLIC_AUTH_PROVIDER 一致,这样服务端路由、 中间件、React hooks 和 Landing 页会加载同一条 provider 路径。

提供商最适合说明
Better Auth自托管或合规敏感部署默认。开源、Postgres 后端,通过官方 oneTap 插件支持 Google One Tap。
NextAuth / Auth.js v5自托管且 OAuth 场景较多的部署使用 Auth.js 会话 Cookie 和 Nebutra 自有 Google One Tap 回调。
Clerk托管认证和托管 UI 组件使用 Clerk 官方 SDK 与 <GoogleOneTap /> 组件。
Supabase Auth已使用 Supabase 的团队与 Supabase storage/realtime 部署配套。
Dev仅本地 fixture 预览合成用户和工作区;生产环境会硬失败。
AUTH_PROVIDER=better-auth
NEXT_PUBLIC_AUTH_PROVIDER=better-auth

Google One Tap

Landing 页会根据 NEXT_PUBLIC_AUTH_PROVIDER 选择正确的 One Tap 实现:

ProviderOne Tap 实现必需公开配置
Better Authbetter-auth 客户端 oneTapClient,POST 到 /api/auth/one-tap/callbackNEXT_PUBLIC_GOOGLE_CLIENT_ID
NextAuthGoogle Identity Services HTML API,POST 到 /api/auth/google-one-tapNEXT_PUBLIC_GOOGLE_CLIENT_ID
ClerkClerk 官方 <GoogleOneTap /> 组件NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY

设置 NEXT_PUBLIC_ENABLE_GOOGLE_ONE_TAP=false 可关闭 Landing 页提示。 当 ACCESS_GATE_MODE=invite 时,OAuth 与 One Tap 入口会被封住,直到邀请码门禁放开。

Better Auth(生产默认)

生产 Nebutra 使用独立登录中心apps/authhttps://auth.nebutra.com):

变量示例
AUTH_PROVIDERbetter-auth
BETTER_AUTH_URL / NEXT_PUBLIC_AUTH_URLhttps://auth.nebutra.com
AUTH_COOKIE_DOMAIN.nebutra.com
BETTER_AUTH_SECRETauth 与 web 相同

单一登录入口

产品应用是 RP:会把认证相关路由 soft-redirect 到登录中心。Better Auth 只有一套 UI,不要在 app 上再维护第二套登录页。

表面行为
app.nebutra.com/sign-in307auth.nebutra.com/sign-in?returnTo=…
app.nebutra.com/sign-up307auth.nebutra.com/sign-up?returnTo=…
auth.nebutra.com/*规范登录 UI(账密、OAuth、可选魔法链接 / Passkey)

例外:当 NEXT_PUBLIC_AUTH_PROVIDER=clerk 时,web 可保留本地 Clerk UI。

OAuth 回调 URI

在 IdP 中注册登录中心回调(不要写 app):

https://auth.nebutra.com/api/auth/callback/google
https://auth.nebutra.com/api/auth/callback/github

登录中心 GET /health 会返回当前启用的 oauth.callbackUrls

验证码 / 魔法链接 / Passkey

开关 / 环境变量作用
NEXT_PUBLIC_TURNSTILE_SITE_KEY + TURNSTILE_SECRET_KEY表单 Cloudflare Turnstile(x-captcha-response
NEXT_PUBLIC_AUTH_MAGIC_LINK=1登录页展示魔法链接入口
NEXT_PUBLIC_AUTH_PASSKEYS=1Passkey 按钮与条件 UI
PASSKEY_RP_ID / PASSKEY_ORIGINWebAuthn RP 覆盖(默认 auth 主机)

各 RP 的 BETTER_AUTH_SECRET 必须一致。

Clerk 配置(可选提供商)

1. 安装 Clerk

pnpm add @clerk/nextjs

2. 添加环境变量

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxx
CLERK_SECRET_KEY=sk_live_xxxxxxxxxxxx
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxx

3. 包裹应用

import { ClerkProvider } from "@clerk/nextjs";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider>
      <html lang="zh">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

4. 添加认证代理

import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";

const isPublicRoute = createRouteMatcher(["/", "/sign-in(.*)", "/sign-up(.*)"]);

export default clerkMiddleware(async (auth, req) => {
  if (!isPublicRoute(req)) {
    await auth.protect();
  }
});

5. 在 Server Components 中读取认证信息

import { auth, currentUser } from "@clerk/nextjs/server";

export default async function DashboardPage() {
  const { orgId } = await auth();
  const user = await currentUser();

  if (!orgId) redirect("/create-org");

  return <Dashboard userId={user?.id} orgId={orgId} />;
}

网关令牌校验

Hono API 网关在受保护请求上按当前 AUTH_PROVIDER 校验会话 / Bearer。 Better Auth 使用共享密钥与数据库会话;服务间调用使用短时 HS256 x-service-tokenSERVICE_SECRET),旧版 hex-HMAC 会被拒绝。

JWT 声明内容

经过验证的用户令牌通常包含:

{
  "sub": "user_2a8bXXXXXXXXX",
  "org_id": "org_2a8bXXXXXXXXX",
  "org_role": "org:admin",
  "scopes": ["project:read", "project:create"],
  "plan": "pro"
}

会话管理

Better Auth(生产默认):会话 Cookie 在 auth.nebutra.com 签发, AUTH_COOKIE_DOMAIN=.nebutra.com,RP 经 returnTo 回跳后共享同一 Cookie。

Clerk(可选):会话时长在 Clerk Dashboard 配置,SDK 负责刷新。

登录 / 注册 UI

生产(Better Auth)使用 apps/auth 登录中心页面;产品应用只做 307 跳转。 仅在 AUTH_PROVIDER=clerk 时在 web 本地保留 Clerk <SignIn /> 等组件。

组织创建流程

注册后没有组织的用户会被重定向到组织创建 / onboarding(按提供商不同)。

Clerk 示例:

import { CreateOrganization } from "@clerk/nextjs";

export default function CreateOrgPage() {
  return <CreateOrganization afterCreateOrganizationUrl="/dashboard" />;
}

缺少组织创建路径时,用户可能长期处于 orgId: null 并在落地页与仪表板之间循环跳转。多租户应用务必实现该流程。

相关文档

How is this guide?

目录