- 数据库
- 后端
【免费下载链接】convex-backend
The open-source reactive database for app developers
Clerk 是托管式身份认证服务,而 Convex 通过 JWT 校验与auth.config.ts声明式配置即可无缝接入。本文以 convex-backend 仓库中 clerk.md 技能参考文档为主体,结合仓库内convex/server源码与官方示例,完整讲解从创建 Clerk 应用、配置环境变量,到前端接入ConvexProviderWithClerk、后端读取ctx.auth.getUserIdentity()的端到端流程,并覆盖生产部署与常见坑点排查。
何时选择 Clerk
Clerk 适合两类场景:
- 应用已经在使用 Clerk,希望让 Convex 复用现有用户体系;
- 用户希望直接享受 Clerk 提供的托管式认证功能(登录页、社交登录、多因素认证、组织管理等开箱即用的能力),而不愿自己搭建认证服务。
在开始前,务必先阅读 Convex 官方文档中的 Clerk 接入指南与 Clerk 官方提供的 Convex 数据库集成指南,再动手写配置代码——这是该技能文档反复强调的第一原则。
整体工作流程
整个集成过程遵循如下步骤:
- 与用户确认是否使用 Clerk;
- 确认用户已有 Clerk 账户与 Clerk 应用;
- 判断应用框架:React、Next.js 或 TanStack Start;
- 询问用户当前只需要本地开发配置,还是需要生产就绪配置;
- 收集 Clerk 密钥(publishable key、secret key)与 Clerk Frontend API URL;
- 按官方文档中对应框架的章节执行;
- 完成后端(
convex/auth.config.ts)与前端(Provider 包裹)接线; - 验证登录后 Convex 能正确识别用户为已认证状态;
- 若用户要求生产就绪,确保生产环境的 Clerk 配置也已覆盖。
其中第 4 步(dev-only 还是 production-ready)是贯穿全流程的关键决策,它决定了后续环境变量与 issuer 配置的收集范围。
前置准备:创建 Clerk 账户与应用
如果用户还没有 Clerk 环境,引导其在 Clerk 控制台完成两步操作:
- 注册账户:访问 Clerk 控制台的注册页面创建账户;
- 创建应用:在应用创建页面新建一个 Clerk application。
创建完成后,需要获取两类凭据:
- Publishable Key(公开密钥):用于前端环境变量(Vite 应用为
VITE_CLERK_PUBLISHABLE_KEY,Next.js 为NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY); - Secret Key(私密密钥):仅 Next.js 服务端场景需要,对应
CLERK_SECRET_KEY。
这两类密钥都从 Clerk 的API Keys 页面复制。需要注意:Clonk 的 API Keys 页面只用于获取 publishable key 与 secret key,不要从这里找 Convex 用的 issuer 地址。
关键配置:convex/auth.config.ts
convex/auth.config.ts是 Convex 后端校验第三方 JWT 的唯一入口。它导出一个AuthConfig类型对象,该类型定义在仓库 npm-packages/convex/src/server/authentication.ts 中:
export type AuthConfig = { providers: AuthProvider[]; };AuthProvider支持两种形态:
- OIDC 提供者(Clerk 属于此类):包含
domain(OIDC 提供者的域名,即 Clerk 的 issuer domain)与applicationID(token 的 audience 中必须包含的应用 ID)两个字段; - 自定义 JWT 提供者:
type: "customJwt",需要issuer、jwks(JWKS 公钥端点 URL)与algorithm(目前仅支持RS256和ES256)。
因此 Clerk 场景下的最小配置如下:
import { AuthConfig } from "convex/server"; export default { providers: [ { domain: "https://your-clerk-issuer-domain.clerk.accounts.dev", applicationID: "convex", }, ], } satisfies AuthConfig;其中domain取自 Clerk 控制台Convex 集成设置页(Activate the Convex integration)上展示的Frontend API URL / issuer domain;applicationID对应 Clerk 的 Convex 集成中约定的 audience(convex)。一旦修改了该文件,必须重新运行常规的 Convex dev 或 deploy 流程,后端才会加载新配置。
为什么必须创建该文件
仓库内 waitlist 示例的 AI 辅助文档 npm-packages/private-demos/waitlist/convex/_generated/ai/guidelines.md 中明确强调:
Convex 支持基于 JWT 的认证,通过
convex/auth.config.ts配置。使用认证时必须创建此文件,否则ctx.auth.getUserIdentity()将永远返回null。
环境变量清单
完整的环境变量预期如下:
| 变量 | 用途 | 适用场景 |
|---|---|---|
CLERK_JWT_ISSUER_DOMAIN | Convex 后端校验 JWT 的 issuer 域名 | Convex 官方文档约定 |
CLERK_FRONTEND_API_URL | Clerk Frontend API URL | Clerk 官方文档约定 |
VITE_CLERK_PUBLISHABLE_KEY | Clerk publishable key | Vite / React 应用 |
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | Clerk publishable key | Next.js 应用 |
CLERK_SECRET_KEY | Clerk secret key | Next.js 服务端 |
最容易混淆的一点:CLERK_JWT_ISSUER_DOMAIN与CLERK_FRONTEND_API_URL指向的是同一个值(Clerk Frontend API URL),不要把它们当成两个不同的 URL 分别填写。
前端接入:ClerkProvider+ConvexProviderWithClerk
组件层级与接线
前端接入的核心是替换原先的ConvexProvider,改为同时使用 Clerk 的ClerkProvider与 Convex 的ConvexProviderWithClerk:
import { ClerkProvider, useAuth } from "@clerk/clerk-react"; import { ConvexProviderWithClerk } from "convex/react-clerk"; import { ConvexReactClient } from "convex/react"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL); <ClerkProvider publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}> <ConvexProviderWithClerk client={convex} useAuth={useAuth}> {/* App 内容 */} </ConvexProviderWithClerk> </ClerkProvider>对于 Next.js App Router,需要额外注意服务端与客户端边界:ConvexProviderWithClerk的包裹逻辑必须放在客户端组件中,创建 Convex provider wrapper 时保持清晰的 server/client 边界。
底层实现原理
ConvexProviderWithClerk定义在仓库 npm-packages/convex/src/react-clerk/ConvexProviderWithClerk.tsx 中。从源码可以看到它的关键逻辑:
- 它接收
useAuth(来自@clerk/react、@clerk/nextjs等 React 系 Clerk 客户端库的 hook)与client(ConvexReactClient); - 通过
useAuthFromClerk将 Clerk 的认证状态适配为 Convex 期望的{ isLoading, isAuthenticated, fetchAccessToken }形态,再交给底层的ConvexProviderWithAuth; - token 获取策略:若
sessionClaims?.aud === "convex",说明用户走的是 Clerk 的 Convex 集成,直接调用getToken({ skipCache });否则回退到 JWT token template 模式,调用getToken({ template: "convex", skipCache }); - 每当
orgId、orgRole、sessionId变化时,会重建fetchAccessToken并触发setAuth(),从而让 Convex 客户端感知到会话上下文变化(如切换组织)。
ConvexProviderWithAuth则实现在 npm-packages/convex/src/react/ConvexAuthState.tsx 中,它负责维护isConvexAuthenticated状态——即后端是否确认了当前 token 有效。它的isAuthenticated是authProviderAuthenticated && (isConvexAuthenticated ?? false)的合取结果,这也是文档强调"不要只确认 Clerk 登录成功,还要确认 Convex 也认可会话"的源码依据。
认证感知 UI:useConvexAuth与条件渲染组件
Convex 提供了一组认证感知的 React 组件与 hook,用于按认证状态渲染界面:
useConvexAuth():返回{ isLoading, isAuthenticated, isRefreshing };Authenticated:仅当 Convex 确认已认证时渲染子树;Unauthenticated:仅当未认证时渲染子树;AuthLoading:认证状态尚未确认时渲染(例如正在等待后端校验 token)。
关键原则:在判断"Convex 认证过的 UI 是否可以渲染"时,优先使用useConvexAuth(),而不是直接读取 Clerk 的原始认证状态。原因在于useConvexAuth()的isAuthenticated是前端登录态与后端 token 校验结果的合取——Clerk 侧登录成功但 token 不被 Convex 接受时,它仍会返回未认证,从而避免出现"登录成功但请求全部 401"的割裂体验。
后端读取用户身份:ctx.auth.getUserIdentity()
在 Convex 的 query、mutation、action 中,通过ctx.auth.getUserIdentity()获取当前用户身份:
import { query } from "./_generated/server"; export const me = query({ handler: async (ctx) => { const identity = await ctx.auth.getUserIdentity(); if (identity === null) { throw new Error("Not authenticated"); } return { name: identity.name, email: identity.email, tokenIdentifier: identity.tokenIdentifier, }; }, });UserIdentity接口同样定义在 npm-packages/convex/src/server/authentication.ts 中。其中:
tokenIdentifier(JWT 的sub+iss组合)是稳定且全局唯一的身份标识,是用户表关联时的首选主键;subject对应用户在身份提供者中的sub,跨提供者不一定唯一;issuer对应iss,即身份提供者的域名;- 其余字段(
name、email、pictureUrl、emailVerified等)均来自 OIDC 标准声明,不保证全部存在,使用时需判空; - 自定义声明可以通过索引签名直接断言类型访问,例如
identity.custom_claim as string。
仓库中的官方示例 npm-packages/private-demos/clerk-initial-auth/README.md 展示了完整用法:用户登录后将信息持久化到users表,每条消息与发送它的用户关联,并提供登出按钮。该示例的运行方式为npm run dev,使用自己的 Clerk 实例时需要准备 publishable key(用于main.tsx)与 JWT template Issuer URL(用于auth.config.ts)。
常见陷阱与排查
认证判断与 token 刷新
- 优先用
useConvexAuth()而非 Clerk 原始状态:Convex 认证状态以 Convex 后端确认为准; - 不要只停留在"Clerk 登录成功":关键检查点是 Convex 也能看到该会话并认证请求——即使 Clerk 侧已登录,若 Convex 校验失败,受保护的查询仍然会失败。
配置修改与集成激活
- 修改
convex/auth.config.ts后,必须重新运行 Convex dev 或 deploy 流程; - Convex 集成未激活的典型症状:Convex 报错"no auth provider matched the token"。此时先确认已在 Clerk 的 Convex 集成设置页激活该集成;
- 激活集成后要完整登出再登录:旧会话可能仍持有一个 Convex 拒绝的旧 token。彻底 sign out 后重新 sign in 再测试,避免误判。
环境与边界
- 不要假设 dev 与 production 的 Clerk 配置相同,生产环境的 issuer domain 与 publishable key 需要单独确认;
- Convex 设置页才是获取 Convex 所用 Frontend API URL 的地方;publishable key 与 secret key 始终从 Clerk API Keys 页面获取;
- 仓库若已使用 Clerk,应保留其现有认证流程,除非用户明确要求变更。
生产就绪配置
在交付前明确询问用户需要 dev-only 还是 production-ready 配置:
- 若选择 production-ready,必须一并提供生产环境的 Clerk 密钥与 issuer 配置;
- 在宣布任务完成前,核对生产环境的 redirect URLs 与生产 Clerk 域名值;
- 除非用户明确要求输出交接文档,否则不要擅自向仓库写入 notes 文件。
验证清单
集成完成后,按以下清单逐项验证(这也来自原技能文档的 Validation 与 Checklist 部分):
- 确认用户确实想要 Clerk,并已明确 dev-only 还是 production-ready
- 已按正确的框架章节(React / Next.js / TanStack Start)完成接线
- Clerk 环境变量已设置(publishable key、issuer domain、必要时 secret key)
convex/auth.config.ts已配置且 Convex 已重新加载- 用户可以用 Clerk 完成登录
- 若是刚激活 Convex 集成,已在完整登出后重新登录验证
- 登录后
useConvexAuth()达到 authenticated 状态 - 受保护的 Convex 查询在认证 UI 内成功执行
- 后端受保护函数中
ctx.auth.getUserIdentity()非null - 若要求生产就绪,生产 Clerk 配置已一并覆盖
参考与延伸
- 技能参考文档:npm-packages/private-demos/waitlist/.agents/skills/convex-setup-auth/references/clerk.md
- 客户端组件实现:npm-packages/convex/src/react-clerk/ConvexProviderWithClerk.tsx
- 认证状态管理:npm-packages/convex/src/react/ConvexAuthState.tsx
AuthConfig与UserIdentity类型定义:npm-packages/convex/src/server/authentication.ts- 官方示例应用(Clerk + 用户表 + 消息关联):npm-packages/private-demos/clerk-initial-auth/README.md
- waitlist 示例中关于
auth.config.ts与ctx.auth.getUserIdentity()的说明:npm-packages/private-demos/waitlist/convex/_generated/ai/guidelines.md
- 数据库
- 后端
【免费下载链接】convex-backend
The open-source reactive database for app developers
相关推荐
Convex 后端集成 Clerk 认证:从 auth.config.ts 到 ConvexProviderWithClerk 的完整接入指南
Convex 后端集成 Clerk 认证:从 auth.config.ts 到 ConvexProviderWithClerk 的完整接入指南 本指南以 con
数据库后端Convex 集成 Clerk 认证完整指南:从 auth.config.ts 到 ConvexProviderWithClerk 的端到端配置
Convex 集成 Clerk 认证完整指南:从 auth.config.ts 到 ConvexProviderWithClerk 的端到端配置 本篇技术指南以
数据库后端Convex 接入 Clerk 鉴权实战:从 `auth.config.ts` 到 `ConvexProviderWithClerk` 的完整集成指南
Convex 接入 Clerk 鉴权实战:从 auth.config.ts 到 ConvexProviderWithClerk 的完整集成指南 在 Convex
数据库后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考