clerk-auth
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClerk Auth - Breaking Changes & Error Prevention Guide
Clerk 身份验证 - 破坏性变更与错误预防指南
Package Versions: @clerk/nextjs@6.36.7, @clerk/backend@2.29.2, @clerk/clerk-react@5.59.2, @clerk/testing@1.13.26
Breaking Changes: Nov 2025 - API version 2025-11-10, Oct 2024 - Next.js v6 async auth()
Last Updated: 2026-01-09
包版本:@clerk/nextjs@6.36.7, @clerk/backend@2.29.2, @clerk/clerk-react@5.59.2, @clerk/testing@1.13.26
破坏性变更:2025年11月 - API版本2025-11-10,2024年10月 - Next.js v6 异步auth()
最后更新时间:2026-01-09
What's New (Dec 2025 - Jan 2026)
新增内容(2025年12月 - 2026年1月)
1. API Keys Beta (Dec 11, 2025) - NEW ✨
1. API Keys测试版(2025年12月11日)- 新增 ✨
User-scoped and organization-scoped API keys for your application. Zero-code UI component.
typescript
// 1. Add the component for self-service API key management
import { APIKeys } from '@clerk/nextjs'
export default function SettingsPage() {
return (
<div>
<h2>API Keys</h2>
<APIKeys /> {/* Full CRUD UI for user's API keys */}
</div>
)
}Backend Verification:
typescript
import { verifyToken } from '@clerk/backend'
// API keys are verified like session tokens
const { data, error } = await verifyToken(apiKey, {
secretKey: process.env.CLERK_SECRET_KEY,
authorizedParties: ['https://yourdomain.com'],
})
// Check token type
if (data?.tokenType === 'api_key') {
// Handle API key auth
}clerkMiddleware Token Types:
typescript
// v6.36.0+: Middleware can distinguish token types
clerkMiddleware((auth, req) => {
const { userId, tokenType } = auth()
if (tokenType === 'api_key') {
// API key auth - programmatic access
} else if (tokenType === 'session_token') {
// Regular session - web UI access
}
})Pricing (Beta = Free):
- Creation: $0.001/key
- Verification: $0.0001/verification
面向应用的用户级和组织级API密钥。零代码UI组件。
typescript
// 1. 添加用于自助式API密钥管理的组件
import { APIKeys } from '@clerk/nextjs'
export default function SettingsPage() {
return (
<div>
<h2>API密钥</h2>
<APIKeys /> {/* 用户API密钥的完整CRUD界面 */}
</div>
)
}后端验证:
typescript
import { verifyToken } from '@clerk/backend'
// API密钥的验证方式与会话令牌相同
const { data, error } = await verifyToken(apiKey, {
secretKey: process.env.CLERK_SECRET_KEY,
authorizedParties: ['https://yourdomain.com'],
})
// 检查令牌类型
if (data?.tokenType === 'api_key') {
// 处理API密钥身份验证
}clerkMiddleware令牌类型:
typescript
// v6.36.0+:中间件可区分令牌类型
clerkMiddleware((auth, req) => {
const { userId, tokenType } = auth()
if (tokenType === 'api_key') {
// API密钥身份验证 - 程序化访问
} else if (tokenType === 'session_token') {
// 常规会话 - Web界面访问
}
})定价(测试版免费):
- 创建:0.001美元/密钥
- 验证:0.0001美元/次验证
2. Next.js 16: proxy.ts Middleware Filename (Dec 2025)
2. Next.js 16:proxy.ts中间件文件名(2025年12月)
⚠️ BREAKING: Next.js 16 changed middleware filename due to critical security vulnerability (CVE disclosed March 2025).
Background: The March 2025 vulnerability (affecting Next.js 11.1.4-15.2.2) allowed attackers to completely bypass middleware-based authorization by adding a single HTTP header: . This affected all auth libraries (NextAuth, Clerk, custom solutions).
x-middleware-subrequest: trueWhy the Rename: The → change isn't just cosmetic - it's Next.js signaling that middleware-first security patterns are dangerous. Future auth implementations should not rely solely on middleware for authorization.
middleware.tsproxy.tsNext.js 15 and earlier: middleware.ts
Next.js 16+: proxy.tsCorrect Setup for Next.js 16:
typescript
// src/proxy.ts (NOT middleware.ts!)
import { clerkMiddleware } from '@clerk/nextjs/server'
export default clerkMiddleware()
export const config = {
matcher: [
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
'/(api|trpc)(.*)',
],
}Minimum Version: @clerk/nextjs@6.35.0+ required for Next.js 16 (fixes Turbopack build errors and cache invalidation on sign-out).
⚠️ 破坏性变更:由于严重安全漏洞(2025年3月披露的CVE),Next.js 16更改了中间件文件名。
背景:2025年3月的漏洞(影响Next.js 11.1.4-15.2.2版本)允许攻击者通过添加单个HTTP头完全绕过基于中间件的授权。该漏洞影响所有身份验证库(NextAuth、Clerk、自定义解决方案)。
x-middleware-subrequest: true重命名原因: → 的变更并非只是表面改动——这是Next.js发出的信号:以中间件为核心的安全模式存在风险。未来的身份验证实现不应仅依赖中间件进行授权。
middleware.tsproxy.tsNext.js 15及更早版本:middleware.ts
Next.js 16及以上版本:proxy.tsNext.js 16正确配置:
typescript
// src/proxy.ts(不是middleware.ts!)
import { clerkMiddleware } from '@clerk/nextjs/server'
export default clerkMiddleware()
export const config = {
matcher: [
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
'/(api|trpc)(.*)',
],
}最低版本要求:@clerk/nextjs@6.35.0+ 支持Next.js 16(修复了Turbopack构建错误和登出时的缓存失效问题)。
3. Force Password Reset (Dec 19, 2025)
3. 强制密码重置(2025年12月19日)
Administrators can mark passwords as compromised and force reset:
typescript
import { clerkClient } from '@clerk/backend'
// Force password reset for a user
await clerkClient.users.updateUser(userId, {
passwordDigest: 'compromised', // Triggers reset on next sign-in
})管理员可标记密码为已泄露并强制用户重置:
typescript
import { clerkClient } from '@clerk/backend'
// 强制用户重置密码
await clerkClient.users.updateUser(userId, {
passwordDigest: 'compromised', // 触发下次登录时的重置流程
})4. Organization Reports & Filters (Dec 15-17, 2025)
4. 组织报告与筛选(2025年12月15-17日)
Dashboard now includes org creation metrics and filtering by name/slug/date.
控制台现在包含组织创建指标,支持按名称/别名/日期筛选。
API Version 2025-11-10 Breaking Changes
API版本2025-11-10破坏性变更
1. API Version 2025-11-10 (Nov 10, 2025) - BREAKING CHANGES ⚠️
1. API版本2025-11-10(2025年11月10日)- 破坏性变更 ⚠️
Affects: Applications using Clerk Billing/Commerce APIs
Critical Changes:
-
Endpoint URLs:→
/commerce/(30+ endpoints)/billing/GET /v1/commerce/plans → GET /v1/billing/plans GET /v1/commerce/statements → GET /v1/billing/statements POST /v1/me/commerce/checkouts → POST /v1/me/billing/checkouts -
Field Terminology:→
payment_sourcepayment_methodtypescript// OLD (deprecated) { payment_source_id: "...", payment_source: {...} } // NEW (required) { payment_method_id: "...", payment_method: {...} } -
Removed Fields: Plans responses no longer include:
- ,
amount(useamount_formattedinstead)fee.amount - ,
currency(use fee objects)currency_symbol - (use
payer_type)for_payer_type - ,
annual_monthly_amountannual_amount
-
Removed Endpoints:
- Invoices endpoint (use statements)
- Products endpoint
-
Null Handling: Explicit rules -means "doesn't exist", omitted means "not asserting existence"
null
Migration: Update SDK to v6.35.0+ which includes support for API version 2025-11-10.
影响范围:使用Clerk Billing/Commerce API的应用
关键变更:
-
端点URL:→
/commerce/(30+个端点)/billing/GET /v1/commerce/plans → GET /v1/billing/plans GET /v1/commerce/statements → GET /v1/billing/statements POST /v1/me/commerce/checkouts → POST /v1/me/billing/checkouts -
字段术语:→
payment_sourcepayment_methodtypescript// 旧版(已废弃) { payment_source_id: "...", payment_source: {...} } // 新版(必填) { payment_method_id: "...", payment_method: {...} } -
移除的字段:计划响应不再包含以下字段:
- ,
amount(改用amount_formatted)fee.amount - ,
currency(改用fee对象)currency_symbol - (改用
payer_type)for_payer_type - ,
annual_monthly_amountannual_amount
-
移除的端点:
- 发票端点(改用对账单)
- 产品端点
-
Null值处理:明确规则 -表示“不存在”,省略表示“不声明存在性”
null
迁移建议:将SDK更新至v6.35.0+,该版本支持API版本2025-11-10。
2. Next.js v6 Async auth() (Oct 2024) - BREAKING CHANGE ⚠️
2. Next.js v6 异步auth()(2024年10月)- 破坏性变更 ⚠️
Affects: All Next.js Server Components using
auth()typescript
// ❌ OLD (v5 - synchronous)
const { userId } = auth()
// ✅ NEW (v6 - asynchronous)
const { userId } = await auth()Also affects: is now async in middleware
auth.protect()typescript
// ❌ OLD (v5)
auth.protect()
// ✅ NEW (v6)
await auth.protect()Compatibility: Next.js 15, 16 supported. Static rendering by default.
影响范围:所有使用的Next.js服务器组件
auth()typescript
// ❌ 旧版(v5 - 同步)
const { userId } = auth()
// ✅ 新版(v6 - 异步)
const { userId } = await auth()同时影响:在中间件中现在也是异步的
auth.protect()typescript
// ❌ 旧版(v5)
auth.protect()
// ✅ 新版(v6)
await auth.protect()兼容性:支持Next.js 15、16。默认启用静态渲染。
3. PKCE Support for Custom OAuth (Nov 12, 2025)
3. 自定义OAuth的PKCE支持(2025年11月12日)
Custom OIDC providers and social connections now support PKCE (Proof Key for Code Exchange) for enhanced security in native/mobile applications where client secrets cannot be safely stored.
Use case: Mobile apps, native apps, public clients that can't securely store secrets.
自定义OIDC提供商和社交连接现在支持PKCE(授权码交换证明密钥),增强了原生/移动应用的安全性,此类应用无法安全存储客户端密钥。
适用场景:移动应用、原生应用、无法安全存储密钥的公共客户端。
4. Client Trust: Credential Stuffing Defense (Nov 14, 2025)
4. 客户端信任:凭证填充防御(2025年11月14日)
Automatic secondary authentication when users sign in from unrecognized devices:
- Activates for users with valid passwords but no 2FA
- No configuration required
- Included in all Clerk plans
How it works: Clerk automatically prompts for additional verification (email code, backup code) when detecting sign-in from new device.
当用户从未识别设备登录时,自动触发二次身份验证:
- 适用于拥有有效密码但未启用2FA的用户
- 无需配置
- 所有Clerk套餐均包含
工作原理:Clerk检测到新设备登录时,自动提示进行额外验证(邮件验证码、备用验证码)。
5. Next.js 16 Support (Nov 2025)
5. Next.js 16支持(2025年11月)
@clerk/nextjs v6.35.2+ includes cache invalidation improvements for Next.js 16 during sign-out.
@clerk/nextjs v6.35.2+ 包含Next.js 16登出时的缓存失效改进。
Critical Patterns & Error Prevention
关键模式与错误预防
Next.js v6: Async auth() Helper
Next.js v6:异步auth()助手
Pattern:
typescript
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
const { userId } = await auth() // ← Must await
if (!userId) {
return <div>Unauthorized</div>
}
return <div>User ID: {userId}</div>
}模式示例:
typescript
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
const { userId } = await auth() // ← 必须使用await
if (!userId) {
return <div>未授权</div>
}
return <div>用户ID:{userId}</div>
}Cloudflare Workers: authorizedParties (CSRF Prevention)
Cloudflare Workers:authorizedParties(CSRF预防)
CRITICAL: Always set to prevent CSRF attacks
authorizedPartiestypescript
import { verifyToken } from '@clerk/backend'
const { data, error } = await verifyToken(token, {
secretKey: c.env.CLERK_SECRET_KEY,
// REQUIRED: Prevent CSRF attacks
authorizedParties: ['https://yourdomain.com'],
})Why: Without , attackers can use valid tokens from other domains.
authorizedParties至关重要:始终设置以防止CSRF攻击
authorizedPartiestypescript
import { verifyToken } from '@clerk/backend'
const { data, error } = await verifyToken(token, {
secretKey: c.env.CLERK_SECRET_KEY,
// 必填:防止CSRF攻击
authorizedParties: ['https://yourdomain.com'],
})原因:如果不设置,攻击者可使用来自其他域名的有效令牌。
authorizedPartiesclerkMiddleware() Configuration
clerkMiddleware()配置
Route Protection Patterns
路由保护模式
typescript
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
// Define protected routes
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)',
'/api/private(.*)',
])
const isAdminRoute = createRouteMatcher(['/admin(.*)'])
export default clerkMiddleware(async (auth, req) => {
// Protect routes
if (isProtectedRoute(req)) {
await auth.protect() // Redirects unauthenticated users
}
// Require specific permissions
if (isAdminRoute(req)) {
await auth.protect({
role: 'org:admin', // Requires organization admin role
})
}
})typescript
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
// 定义受保护路由
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)',
'/api/private(.*)',
])
const isAdminRoute = createRouteMatcher(['/admin(.*)'])
export default clerkMiddleware(async (auth, req) => {
// 保护路由
if (isProtectedRoute(req)) {
await auth.protect() // 将未认证用户重定向
}
// 要求特定权限
if (isAdminRoute(req)) {
await auth.protect({
role: 'org:admin', // 需要组织管理员角色
})
}
})All Middleware Options
所有中间件选项
| Option | Type | Description |
|---|---|---|
| | Enable debug logging |
| | JWKS public key for networkless verification |
| | Token time variance (default: 5000ms) |
| | URL-based org activation |
| | Custom sign-in URL |
| | Custom sign-up URL |
| 选项 | 类型 | 描述 |
|---|---|---|
| | 启用调试日志 |
| | 用于无网络验证的JWKS公钥 |
| | 令牌时间偏差(默认:5000ms) |
| | 基于URL的组织激活 |
| | 自定义登录URL |
| | 自定义注册URL |
Organization Sync (URL-based Org Activation)
组织同步(基于URL的组织激活)
⚠️ Next.js Only: This feature currently only works with in Next.js. It does NOT work with in other runtimes (Cloudflare Workers, Express, etc.) due to header checks.
clerkMiddleware()authenticateRequest()Sec-Fetch-DestSource: GitHub Issue #7178
typescript
clerkMiddleware({
organizationSyncOptions: {
organizationPatterns: ['/orgs/:slug', '/orgs/:slug/(.*)'],
personalAccountPatterns: ['/personal', '/personal/(.*)'],
},
})⚠️ 仅Next.js支持:此功能目前仅适用于Next.js中的。由于头检查,它在其他运行时(Cloudflare Workers、Express等)的中无法工作。
clerkMiddleware()Sec-Fetch-DestauthenticateRequest()typescript
clerkMiddleware({
organizationSyncOptions: {
organizationPatterns: ['/orgs/:slug', '/orgs/:slug/(.*)'],
personalAccountPatterns: ['/personal', '/personal/(.*)'],
},
})Webhooks
Webhook
Webhook Verification
Webhook验证
typescript
import { Webhook } from 'svix'
export async function POST(req: Request) {
const payload = await req.text()
const headers = {
'svix-id': req.headers.get('svix-id')!,
'svix-timestamp': req.headers.get('svix-timestamp')!,
'svix-signature': req.headers.get('svix-signature')!,
}
const wh = new Webhook(process.env.CLERK_WEBHOOK_SIGNING_SECRET!)
try {
const event = wh.verify(payload, headers)
// Process event
return Response.json({ success: true })
} catch (err) {
return Response.json({ error: 'Invalid signature' }, { status: 400 })
}
}typescript
import { Webhook } from 'svix'
export async function POST(req: Request) {
const payload = await req.text()
const headers = {
'svix-id': req.headers.get('svix-id')!,
'svix-timestamp': req.headers.get('svix-timestamp')!,
'svix-signature': req.headers.get('svix-signature')!,
}
const wh = new Webhook(process.env.CLERK_WEBHOOK_SIGNING_SECRET!)
try {
const event = wh.verify(payload, headers)
// 处理事件
return Response.json({ success: true })
} catch (err) {
return Response.json({ error: '无效签名' }, { status: 400 })
}
}Common Event Types
常见事件类型
| Event | Trigger |
|---|---|
| New user signs up |
| User profile changes |
| User account deleted |
| New sign-in |
| Sign-out |
| New org created |
| User joins org |
⚠️ Important: Webhook routes must be PUBLIC (no auth). Add to middleware exclude list:
typescript
const isPublicRoute = createRouteMatcher([
'/api/webhooks/clerk(.*)', // Clerk webhooks are public
])
clerkMiddleware((auth, req) => {
if (!isPublicRoute(req)) {
auth.protect()
}
})| 事件 | 触发条件 |
|---|---|
| 新用户注册 |
| 用户资料变更 |
| 用户账户删除 |
| 新登录会话 |
| 用户登出 |
| 新组织创建 |
| 用户加入组织 |
⚠️ 重要提示:Webhook路由必须设为公开(无需身份验证)。添加到中间件排除列表:
typescript
const isPublicRoute = createRouteMatcher([
'/api/webhooks/clerk(.*)', // Clerk Webhook为公开路由
])
clerkMiddleware((auth, req) => {
if (!isPublicRoute(req)) {
auth.protect()
}
})UI Components Quick Reference
UI组件快速参考
| Component | Purpose |
|---|---|
| Full sign-in flow |
| Full sign-up flow |
| Trigger sign-in modal |
| Trigger sign-up modal |
| Render only when authenticated |
| Render only when unauthenticated |
| User menu with sign-out |
| Full profile management |
| Switch between orgs |
| Org settings |
| Create new org |
| API key management (NEW) |
| 组件 | 用途 |
|---|---|
| 完整登录流程 |
| 完整注册流程 |
| 触发登录模态框 |
| 触发注册模态框 |
| 仅在用户已认证时渲染 |
| 仅在用户未认证时渲染 |
| 包含登出选项的用户菜单 |
| 完整资料管理界面 |
| 在组织间切换 |
| 组织设置界面 |
| 创建新组织 |
| API密钥管理(新增) |
React Hooks
React钩子
| Hook | Returns |
|---|---|
| |
| |
| Clerk instance with methods |
| Current session object |
| Current org context |
| All user's orgs |
| 钩子 | 返回值 |
|---|---|
| |
| |
| 包含方法的Clerk实例 |
| 当前会话对象 |
| 当前组织上下文 |
| 用户所属的所有组织 |
JWT Templates - Size Limits & Shortcodes
JWT模板 - 大小限制与短代码
JWT Size Limitation: 1.2KB for Custom Claims ⚠️
JWT大小限制:自定义声明最多1.2KB ⚠️
Problem: Browser cookies limited to 4KB. Clerk's default claims consume ~2.8KB, leaving 1.2KB for custom claims.
⚠️ Development Note: When testing custom JWT claims in Vite dev mode, you may encounter "431 Request Header Fields Too Large" error. This is caused by Clerk's handshake token in the URL exceeding Vite's 8KB limit. See Issue #11 for solution.
Solution:
json
// ✅ GOOD: Minimal claims
{
"user_id": "{{user.id}}",
"email": "{{user.primary_email_address}}",
"role": "{{user.public_metadata.role}}"
}
// ❌ BAD: Exceeds limit
{
"bio": "{{user.public_metadata.bio}}", // 6KB field
"all_metadata": "{{user.public_metadata}}" // Entire object
}Best Practice: Store large data in database, include only identifiers/roles in JWT.
问题:浏览器Cookie限制为4KB。Clerk的默认声明占用约2.8KB,剩余1.2KB用于自定义声明。
⚠️ 开发注意事项:在Vite开发模式下测试自定义JWT声明时,可能会遇到**"431 Request Header Fields Too Large"**错误。这是由于URL中的Clerk握手令牌超过了Vite的8KB限制。解决方案见问题#11。
解决方案:
json
// ✅ 推荐:最小化声明
{
"user_id": "{{user.id}}",
"email": "{{user.primary_email_address}}",
"role": "{{user.public_metadata.role}}"
}
// ❌ 不推荐:超出限制
{
"bio": "{{user.public_metadata.bio}}", // 6KB字段
"all_metadata": "{{user.public_metadata}}" // 整个对象
}最佳实践:将大型数据存储在数据库中,仅在JWT中包含标识符/角色。
Available Shortcodes Reference
可用短代码参考
| Category | Shortcodes | Example |
|---|---|---|
| User ID & Name | | |
| Contact | | |
| Profile | | |
| Verification | | |
| Metadata | | |
| Organization | | |
Advanced Features:
- String Interpolation:
"{{user.last_name}} {{user.first_name}}" - Conditional Fallbacks:
"{{user.public_metadata.role || 'user'}}" - Nested Metadata:
"{{user.public_metadata.profile.interests}}"
Official Docs: https://clerk.com/docs/guides/sessions/jwt-templates
| 类别 | 短代码 | 示例 |
|---|---|---|
| 用户ID与名称 | | |
| 联系方式 | | |
| 资料信息 | | |
| 验证状态 | | |
| 元数据 | | |
| 组织信息 | | |
高级功能:
- 字符串插值:
"{{user.last_name}} {{user.first_name}}" - 条件回退:
"{{user.public_metadata.role || 'user'}}" - 嵌套元数据:
"{{user.public_metadata.profile.interests}}"
Testing with Clerk
使用Clerk进行测试
Test Credentials (Fixed OTP: 424242)
测试凭证(固定OTP:424242)
Test Emails (no emails sent, fixed OTP):
john+clerk_test@example.com
jane+clerk_test@gmail.comTest Phone Numbers (no SMS sent, fixed OTP):
+12015550100
+19735550133Fixed OTP Code: (works for all test credentials)
424242测试邮箱(不发送邮件,固定OTP):
john+clerk_test@example.com
jane+clerk_test@gmail.com测试手机号(不发送短信,固定OTP):
+12015550100
+19735550133固定OTP验证码:(适用于所有测试凭证)
424242Generate Session Tokens (60-second lifetime)
生成会话令牌(有效期60秒)
Script ():
scripts/generate-session-token.jsbash
undefined脚本():
scripts/generate-session-token.jsbash
undefinedGenerate token
生成令牌
CLERK_SECRET_KEY=sk_test_... node scripts/generate-session-token.js
CLERK_SECRET_KEY=sk_test_... node scripts/generate-session-token.js
Create new test user
创建新测试用户
CLERK_SECRET_KEY=sk_test_... node scripts/generate-session-token.js --create-user
CLERK_SECRET_KEY=sk_test_... node scripts/generate-session-token.js --create-user
Auto-refresh token every 50 seconds
每50秒自动刷新令牌
CLERK_SECRET_KEY=sk_test_... node scripts/generate-session-token.js --refresh
**Manual Flow**:
1. Create user: `POST /v1/users`
2. Create session: `POST /v1/sessions`
3. Generate token: `POST /v1/sessions/{session_id}/tokens`
4. Use in header: `Authorization: Bearer <token>`CLERK_SECRET_KEY=sk_test_... node scripts/generate-session-token.js --refresh
**手动流程**:
1. 创建用户:`POST /v1/users`
2. 创建会话:`POST /v1/sessions`
3. 生成令牌:`POST /v1/sessions/{session_id}/tokens`
4. 在请求头中使用:`Authorization: Bearer <token>`E2E Testing with Playwright
使用Playwright进行端到端测试
Install for automatic Testing Token management:
@clerk/testingbash
npm install -D @clerk/testingGlobal Setup ():
global.setup.tstypescript
import { clerkSetup } from '@clerk/testing/playwright'
import { test as setup } from '@playwright/test'
setup('global setup', async ({}) => {
await clerkSetup()
})Test File ():
auth.spec.tstypescript
import { setupClerkTestingToken } from '@clerk/testing/playwright'
import { test } from '@playwright/test'
test('sign up', async ({ page }) => {
await setupClerkTestingToken({ page })
await page.goto('/sign-up')
await page.fill('input[name="emailAddress"]', 'test+clerk_test@example.com')
await page.fill('input[name="password"]', 'TestPassword123!')
await page.click('button[type="submit"]')
// Verify with fixed OTP
await page.fill('input[name="code"]', '424242')
await page.click('button[type="submit"]')
await expect(page).toHaveURL('/dashboard')
})Official Docs: https://clerk.com/docs/guides/development/testing/overview
安装以自动管理测试令牌:
@clerk/testingbash
npm install -D @clerk/testing全局设置():
global.setup.tstypescript
import { clerkSetup } from '@clerk/testing/playwright'
import { test as setup } from '@playwright/test'
setup('全局设置', async ({}) => {
await clerkSetup()
})测试文件():
auth.spec.tstypescript
import { setupClerkTestingToken } from '@clerk/testing/playwright'
import { test } from '@playwright/test'
test('注册', async ({ page }) => {
await setupClerkTestingToken({ page })
await page.goto('/sign-up')
await page.fill('input[name="emailAddress"]', 'test+clerk_test@example.com')
await page.fill('input[name="password"]', 'TestPassword123!')
await page.click('button[type="submit"]')
// 使用固定OTP验证
await page.fill('input[name="code"]', '424242')
await page.click('button[type="submit"]')
await expect(page).toHaveURL('/dashboard')
})Known Issues Prevention
已知问题预防
This skill prevents 15 documented issues:
本指南可预防15个已记录的问题:
Issue #1: Missing Clerk Secret Key
问题#1:缺少Clerk密钥
Error: "Missing Clerk Secret Key or API Key"
Source: https://stackoverflow.com/questions/77620604
Prevention: Always set in or via
.env.localwrangler secret put错误信息:"Missing Clerk Secret Key or API Key"
来源:https://stackoverflow.com/questions/77620604
预防措施:始终在中设置,或通过配置
.env.localwrangler secret putIssue #2: API Key → Secret Key Migration
问题#2:API密钥→密钥迁移
Error: "apiKey is deprecated, use secretKey"
Source: https://clerk.com/docs/upgrade-guides/core-2/backend
Prevention: Replace with in all calls
apiKeysecretKey错误信息:"apiKey is deprecated, use secretKey"
来源:https://clerk.com/docs/upgrade-guides/core-2/backend
预防措施:在所有调用中将替换为
apiKeysecretKeyIssue #3: JWKS Cache Race Condition
问题#3:JWKS缓存竞态条件
Error: "No JWK available"
Source: https://github.com/clerk/javascript/blob/main/packages/backend/CHANGELOG.md
Prevention: Use @clerk/backend@2.17.2 or later (fixed)
错误信息:"No JWK available"
来源:https://github.com/clerk/javascript/blob/main/packages/backend/CHANGELOG.md
预防措施:使用@clerk/backend@2.17.2或更高版本(已修复)
Issue #4: Missing authorizedParties (CSRF)
问题#4:缺少authorizedParties(CSRF)
Error: No error, but CSRF vulnerability
Source: https://clerk.com/docs/reference/backend/verify-token
Prevention: Always set
authorizedParties: ['https://yourdomain.com']错误信息:无错误,但存在CSRF漏洞
来源:https://clerk.com/docs/reference/backend/verify-token
预防措施:始终设置
authorizedParties: ['https://yourdomain.com']Issue #5: Import Path Changes (Core 2)
问题#5:导入路径变更(Core 2)
Error: "Cannot find module"
Source: https://clerk.com/docs/upgrade-guides/core-2/backend
Prevention: Update import paths for Core 2
错误信息:"Cannot find module"
来源:https://clerk.com/docs/upgrade-guides/core-2/backend
预防措施:更新Core 2的导入路径
Issue #6: JWT Size Limit Exceeded
问题#6:JWT大小限制超出
Error: Token exceeds size limit
Source: https://clerk.com/docs/backend-requests/making/custom-session-token
Prevention: Keep custom claims under 1.2KB
错误信息:令牌超出大小限制
来源:https://clerk.com/docs/backend-requests/making/custom-session-token
预防措施:自定义声明保持在1.2KB以内
Issue #7: Deprecated API Version v1
问题#7:已废弃的API版本v1
Error: "API version v1 is deprecated"
Source: https://clerk.com/docs/upgrade-guides/core-2/backend
Prevention: Use latest SDK versions (API v2025-11-10)
错误信息:"API version v1 is deprecated"
来源:https://clerk.com/docs/upgrade-guides/core-2/backend
预防措施:使用最新SDK版本(API v2025-11-10)
Issue #8: ClerkProvider JSX Component Error
问题#8:ClerkProvider JSX组件错误
Error: "cannot be used as a JSX component"
Source: https://stackoverflow.com/questions/79265537
Prevention: Ensure React 19 compatibility with @clerk/clerk-react@5.59.2+
错误信息:"cannot be used as a JSX component"
来源:https://stackoverflow.com/questions/79265537
预防措施:确保React 19与@clerk/clerk-react@5.59.2+兼容
Issue #9: Async auth() Helper Confusion
问题#9:异步auth()助手混淆
Error: "auth() is not a function"
Source: https://clerk.com/changelog/2024-10-22-clerk-nextjs-v6
Prevention: Always await:
const { userId } = await auth()错误信息:"auth() is not a function"
来源:https://clerk.com/changelog/2024-10-22-clerk-nextjs-v6
预防措施:始终使用await:
const { userId } = await auth()Issue #10: Environment Variable Misconfiguration
问题#10:环境变量配置错误
Error: "Missing Publishable Key" or secret leaked
Prevention: Use correct prefixes (, ), never commit secrets
NEXT_PUBLIC_VITE_错误信息:"Missing Publishable Key" 或密钥泄露
预防措施:使用正确的前缀(, ),绝不提交密钥到版本控制系统
NEXT_PUBLIC_VITE_Issue #11: 431 Request Header Fields Too Large (Vite Dev Mode)
问题#11:431 Request Header Fields Too Large(Vite开发模式)
Error: "431 Request Header Fields Too Large" when signing in
Source: Common in Vite dev mode when testing custom JWT claims
Cause: Clerk's token in URL exceeds Vite's 8KB header limit
Prevention:
__clerk_handshakeAdd to :
package.jsonjson
{
"scripts": {
"dev": "NODE_OPTIONS='--max-http-header-size=32768' vite"
}
}Temporary Workaround: Clear browser cache, sign out, sign back in
Why: Clerk dev tokens are larger than production; custom JWT claims increase handshake token size
Note: This is different from Issue #6 (session token size). Issue #6 is about cookies (1.2KB), this is about URL parameters in dev mode (8KB → 32KB).
错误信息:登录时出现"431 Request Header Fields Too Large"
来源:在Vite开发模式下测试自定义JWT声明时常见
原因:URL中的Clerk 令牌超过了Vite的8KB头限制
预防措施:
__clerk_handshake在中添加:
package.jsonjson
{
"scripts": {
"dev": "NODE_OPTIONS='--max-http-header-size=32768' vite"
}
}临时解决方法:清除浏览器缓存,登出后重新登录
原因:Clerk开发令牌比生产环境令牌大;自定义JWT声明会增加握手令牌的大小
注意:此问题与问题#6(会话令牌大小)不同。问题#6是关于Cookie(1.2KB),此问题是关于开发模式下的URL参数(8KB → 32KB)。
Issue #12: User Type Mismatch (useUser vs currentUser)
问题#12:用户类型不匹配(useUser vs currentUser)
Error: TypeScript errors when sharing user utilities across client/server
Source: GitHub Issue #2176
Why It Happens: returns (client-side) with different properties than returns (server-side). Client has , object; server has and instead.
Prevention: Use shared properties only, or create separate utility functions for client vs server contexts.
useUser()UserResourcecurrentUser()UserfullNameprimaryEmailAddressprimaryEmailAddressIdprivateMetadatatypescript
// ✅ CORRECT: Use properties that exist in both
const primaryEmailAddress = user.emailAddresses.find(
({ id }) => id === user.primaryEmailAddressId
)
// ✅ CORRECT: Separate types
type ClientUser = ReturnType<typeof useUser>['user']
type ServerUser = Awaited<ReturnType<typeof currentUser>>错误信息:在客户端/服务器之间共享用户工具时出现TypeScript错误
来源:GitHub Issue #2176
原因:返回(客户端),其属性与返回的(服务器端)不同。客户端有、对象;服务器端有和。
预防措施:仅使用共享属性,或为客户端和服务器上下文创建单独的工具函数。
useUser()UserResourcecurrentUser()UserfullNameprimaryEmailAddressprimaryEmailAddressIdprivateMetadatatypescript
// ✅ 正确:使用双方都存在的属性
const primaryEmailAddress = user.emailAddresses.find(
({ id }) => id === user.primaryEmailAddressId
)
// ✅ 正确:分离类型
type ClientUser = ReturnType<typeof useUser>['user']
type ServerUser = Awaited<ReturnType<typeof currentUser>>Issue #13: Multiple acceptsToken Types Causes token-type-mismatch
问题#13:多种acceptsToken类型导致token-type-mismatch
Error: "token-type-mismatch" when using with multiple token types
Source: GitHub Issue #7520
Why It Happens: When using with multiple values (e.g., ), Clerk incorrectly throws token-type-mismatch error.
Prevention: Upgrade to @clerk/backend@2.29.2+ (fix available in snapshot, releasing soon).
authenticateRequest()authenticateRequest()acceptsToken['session_token', 'api_key']typescript
// This now works in @clerk/backend@2.29.2+
const result = await authenticateRequest(request, {
acceptsToken: ['session_token', 'api_key'], // Fixed!
})错误信息:使用并设置多种令牌类型时出现"token-type-mismatch"
来源:GitHub Issue #7520
原因:当设置多个值(如)时,Clerk会错误地抛出令牌类型不匹配错误。
预防措施:升级到@clerk/backend@2.29.2+(修复已在快照版本中提供,即将正式发布)。
authenticateRequest()authenticateRequest()acceptsToken['session_token', 'api_key']typescript
// @clerk/backend@2.29.2+ 中此问题已修复
const result = await authenticateRequest(request, {
acceptsToken: ['session_token', 'api_key'], // 已修复!
})Issue #14: deriveUrlFromHeaders Server Crash on Malformed URLs
问题#14:deriveUrlFromHeaders在畸形URL下导致服务器崩溃
Error: Server crashes with URL parsing error
Source: GitHub Issue #7275
Why It Happens: Internal function performs unsafe URL parsing and crashes the entire server when receiving malformed URLs in headers (e.g., ). This is a denial-of-service vulnerability.
Prevention: Upgrade to @clerk/backend@2.29.0+ (fixed).
deriveUrlFromHeaders()x-forwarded-host: 'example.com[invalid]'错误信息:服务器因URL解析错误崩溃
来源:GitHub Issue #7275
原因:内部函数执行不安全的URL解析,当收到头中的畸形URL(如)时,会导致整个服务器崩溃。这是一个拒绝服务漏洞。
预防措施:升级到@clerk/backend@2.29.0+(已修复)。
deriveUrlFromHeaders()x-forwarded-host: 'example.com[invalid]'Issue #15: treatPendingAsSignedOut Option for Pending Sessions
问题#15:treatPendingAsSignedOut选项处理待处理会话
Error: None - optional parameter for edge case handling
Source: Changelog @clerk/nextjs@6.32.0
Why It Exists: Sessions can have a status during certain flows (e.g., credential stuffing defense secondary auth). By default, pending sessions are treated as signed-out (user is null).
Usage: Set to treat pending as signed-in (available in @clerk/nextjs@6.32.0+).
pendingtreatPendingAsSignedOut: falsetypescript
// Default: pending = signed out
const user = await currentUser() // null if status is 'pending'
// Treat pending as signed in
const user = await currentUser({ treatPendingAsSignedOut: false }) // defined if pending错误信息:无错误 - 边缘情况处理的可选参数
来源:Changelog @clerk/nextjs@6.32.0
存在原因:在某些流程中(如凭证填充防御二次验证),会话可能处于状态。默认情况下,待处理会话会被视为已登出(用户为null)。
用法:设置将待处理会话视为已登录(@clerk/nextjs@6.32.0+支持)。
pendingtreatPendingAsSignedOut: falsetypescript
// 默认:待处理 = 已登出
const user = await currentUser() // 如果状态为'pending',返回null
// 将待处理视为已登录
const user = await currentUser({ treatPendingAsSignedOut: false }) // 如果待处理则返回用户Production Considerations
生产环境注意事项
Service Availability & Reliability
服务可用性与可靠性
Context: Clerk experienced 3 major service disruptions in May-June 2025 attributed to Google Cloud Platform (GCP) outages. The June 26, 2025 outage lasted 45 minutes (6:16-7:01 UTC) and affected all Clerk customers.
Source: Clerk Postmortem: June 26, 2025
Mitigation Strategies:
- Monitor Clerk Status for real-time updates
- Implement graceful degradation when Clerk API is unavailable
- Cache auth tokens locally where possible
- For existing sessions, use option for networkless verification:
jwtKey
typescript
clerkMiddleware({
jwtKey: process.env.CLERK_JWT_KEY, // Allows offline token verification
})Note: During total outage, no new sessions can be created (auth requires Clerk API). However, existing sessions can continue working if you verify JWTs locally with . Clerk committed to exploring multi-cloud redundancy to reduce single-vendor dependency risk.
jwtKey背景:2025年5-6月,Clerk因Google Cloud Platform(GCP)故障经历了3次重大服务中断。2025年6月26日的中断持续了45分钟(UTC时间6:16-7:01),影响了所有Clerk客户。
缓解策略:
- 监控Clerk状态页获取实时更新
- 当Clerk API不可用时,实现优雅降级
- 尽可能在本地缓存身份验证令牌
- 对于现有会话,使用选项进行无网络验证:
jwtKey
typescript
clerkMiddleware({
jwtKey: process.env.CLERK_JWT_KEY, // 支持离线令牌验证
})注意:在完全中断期间,无法创建新会话(身份验证需要Clerk API)。但如果使用本地验证JWT,现有会话可继续工作。Clerk承诺探索多云冗余以降低单一供应商依赖风险。
jwtKeyOfficial Documentation
官方文档
- Clerk Docs: https://clerk.com/docs
- Next.js Guide: https://clerk.com/docs/references/nextjs/overview
- React Guide: https://clerk.com/docs/references/react/overview
- Backend SDK: https://clerk.com/docs/reference/backend/overview
- JWT Templates: https://clerk.com/docs/guides/sessions/jwt-templates
- API Version 2025-11-10 Upgrade: https://clerk.com/docs/guides/development/upgrading/upgrade-guides/2025-11-10
- Testing Guide: https://clerk.com/docs/guides/development/testing/overview
- Context7 Library ID:
/clerk/clerk-docs
- Clerk文档:https://clerk.com/docs
- Next.js指南:https://clerk.com/docs/references/nextjs/overview
- React指南:https://clerk.com/docs/references/react/overview
- 后端SDK:https://clerk.com/docs/reference/backend/overview
- JWT模板:https://clerk.com/docs/guides/sessions/jwt-templates
- API版本2025-11-10升级:https://clerk.com/docs/guides/development/upgrading/upgrade-guides/2025-11-10
- 测试指南:https://clerk.com/docs/guides/development/testing/overview
- Context7库ID:
/clerk/clerk-docs
Package Versions
包版本
Latest (Nov 22, 2025):
json
{
"dependencies": {
"@clerk/nextjs": "^6.36.7",
"@clerk/clerk-react": "^5.59.2",
"@clerk/backend": "^2.29.2",
"@clerk/testing": "^1.13.26"
}
}Token Efficiency:
- Without skill: ~6,500 tokens (setup tutorials, JWT templates, testing setup, webhooks, production considerations)
- With skill: ~3,200 tokens (breaking changes + critical patterns + error prevention + production guidance)
- Savings: ~51% (~3,300 tokens)
Errors prevented: 15 documented issues with exact solutions
Key value: API Keys beta, Next.js 16 proxy.ts (with March 2025 CVE context), clerkMiddleware() options, webhooks, component reference, API 2025-11-10 breaking changes, JWT size limits, user type mismatches, production considerations (GCP outages, jwtKey offline verification)
Last verified: 2026-01-20 | Skill version: 3.1.0 | Changes: Added 4 new Known Issues (#12-15: user type mismatch, acceptsToken type mismatch, deriveUrlFromHeaders crash, treatPendingAsSignedOut option), expanded proxy.ts section with March 2025 CVE security context, added Production Considerations section (GCP outages + mitigation), added organizationSyncOptions Next.js-only limitation note, updated minimum version requirements for Next.js 16 (6.35.0+).
最新版本(2025年11月22日):
json
{
"dependencies": {
"@clerk/nextjs": "^6.36.7",
"@clerk/clerk-react": "^5.59.2",
"@clerk/backend": "^2.29.2",
"@clerk/testing": "^1.13.26"
}
}令牌效率:
- 未使用本指南:约6500令牌(设置教程、JWT模板、测试设置、Webhook、生产注意事项)
- 使用本指南:约3200令牌(破坏性变更+关键模式+错误预防+生产指导)
- 节省:约51%(约3300令牌)
预防的错误:15个带确切解决方案的已记录问题
核心价值:API Keys测试版、Next.js 16 proxy.ts(含2025年3月CVE安全背景)、clerkMiddleware()选项、Webhook、组件参考、API 2025-11-10破坏性变更、JWT大小限制、用户类型不匹配、生产环境注意事项(GCP故障、jwtKey离线验证)
最后验证时间:2026-01-20 | 指南版本:3.1.0 | 变更内容:新增4个已知问题(#12-15:用户类型不匹配、acceptsToken类型不匹配、deriveUrlFromHeaders崩溃、treatPendingAsSignedOut选项),扩展proxy.ts部分的2025年3月CVE安全背景,新增生产环境注意事项部分(GCP故障+缓解措施),添加organizationSyncOptions仅Next.js支持的限制说明,更新Next.js 16的最低版本要求(6.35.0+)。