关于 clerk-nextjs-skills
面向 Next.js 开发者的 Clerk 集成技能,说明用户认证、路由保护、用户数据读取及 Next.js 版本迁移。还提供使用 Vercel 适配器和 Clerk 工具构建带 OAuth 验证的 MCP 服务的配置指引。
主要功能
- 01配置 Clerk 用户认证
- 02保护 Next.js 路由
- 03读取客户端与服务端用户数据
- 04迁移 middleware.ts 至 proxy.ts
- 05设置带 OAuth 验证的 MCP 服务
适用场景
- 01为 Next.js 应用添加登录与注册
- 02限制未认证用户访问指定路由
- 03将 Next.js 15 项目迁移到 16
- 04为 MCP 工具验证 Clerk OAuth 令牌
MCP 相关
指导使用 @vercel/mcp-adapter 和 @clerk/mcp-tools 在 Next.js 中构建 MCP 服务,并配置 Clerk OAuth 令牌验证和动态客户端注册。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gocallum/ nextjs16-agent-skills --skill clerk-nextjs-skills安装后在 Claude Code 中输入/clerk-nextjs-skills确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CREATION_SUMMARY.mdQUICK_REFERENCE.mdREADME.mdreferences/CLERK_ENV_SETUP.mdCLERK_MCP_SERVER_SETUP.mdEXAMPLES.mdPROXY_MIGRATION.mdscripts/setup-clerk-nextjs.sh详细介绍
链接
- Clerk Next.js 快速入门
- Clerk MCP 服务指南
- Clerk Next.js SDK 参考
- clerkMiddleware() 参考
- 读取用户数据
- 保护路由
- OAuth 令牌验证
- Clerk 控制面板
- @vercel/mcp-adapter
- @clerk/mcp-tools
- MCP 示例代码库
快速开始
1. 安装依赖(使用 pnpm)
pnpm add @clerk/nextjs
# For MCP server integration, also install:
pnpm add @vercel/mcp-adapter @clerk/mcp-tools
2. 创建 proxy.ts(Next.js 16)
proxy.ts 文件取代了 Next.js 15 中的 middleware.ts。在项目根目录或 /src 中创建该文件:
// proxy.ts (or src/proxy.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)(.*)',
],
}
3. 设置环境变量
在项目根目录中创建 .env.local:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_publishable_key_here
CLERK_SECRET_KEY=your_secret_key_here
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
4. 将 ClerkProvider 添加到布局中
// app/layout.tsx
import {
ClerkProvider,
SignInButton,
SignUpButton,
SignedIn,
SignedOut,
UserButton,
} from '@clerk/nextjs'
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'My App',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<ClerkProvider>
<html lang="en">
<body>
<header className="flex justify-end items-center p-4 gap-4 h-16">
<SignedOut>
<SignInButton />
<SignUpButton />
</SignedOut>
<SignedIn>
<UserButton />
</SignedIn>
</header>
{children}
</body>
</html>
</ClerkProvider>
)
}
5. 运行应用
pnpm dev
访问 http://localhost:3000,然后点击“注册”以创建首位用户。
核心概念
proxy.ts 与 middleware.ts
- Next.js 16(App Router):使用
proxy.ts配置 Clerk 中间件 - Next.js ≤15:使用
middleware.ts,代码相同(仅文件名不同) - 无论文件名如何,Clerk 的
clerkMiddleware()函数都相同 matcher配置可确保正确处理路由并提升性能
保护路由
默认情况下,clerkMiddleware() 不会保护路由——所有路由都是公开的。使用 auth.protect() 要求进行身份验证:
// Protect specific route
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
const { userId } = await auth()
if (!userId) {
// Redirect handled by clerkMiddleware
}
return <div>Protected content for {userId}</div>
}
或者在 proxy.ts 中保护所有路由:
import { clerkMiddleware } from '@clerk/nextjs/server'
export default clerkMiddleware(async (auth, req) => {
await auth.protect()
})
环境变量验证
在运行时之前检查必需的 Clerk 密钥:
// lib/clerk-config.ts
export function validateClerkEnv() {
const required = [
'NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY',
'CLERK_SECRET_KEY',
]
const missing = required.filter(key => !process.env[key])
if (missing.length > 0) {
throw new Error(`Missing required Clerk environment variables: ${missing.join(', ')}`)
}
}
访问用户数据
在客户端组件中使用 Clerk 钩子:
// app/components/user-profile.tsx
'use client'
import { useUser } from '@clerk/nextjs'
export function UserProfile() {
const { user, isLoaded } = useUser()
if (!isLoaded) return <div>Loading...</div>
if (!user) return <div>Not signed in</div>
return (
<div>
<h1>{user.fullName}</h1>
<p>{user.primaryEmailAddress?.emailAddress}</p>
</div>
)
}
或者在服务端组件/操作中使用:
// app/actions.ts
'use server'
import { auth, clerkClient } from '@clerk/nextjs/server'
export async function getUserData() {
const { userId } = await auth()
if (!userId) {
throw new Error('Unauthorized')
}
const clerk = await clerkClient()
const user = await clerk.users.getUser(userId)
return user
}
从 middleware.ts(Next.js 15)迁移到 proxy.ts(Next.js 16)
逐步迁移
-
重命名文件,将
middleware.ts改为proxy.ts(位置不变:项目根目录或/src) -
保持代码不变——无需进行功能性更改:
// Before (middleware.ts) import { clerkMiddleware } from '@clerk/nextjs/server' export default clerkMiddleware() export const config = { ... } // After (proxy.ts) - Same code import { clerkMiddleware } from '@clerk/nextjs/server' export default clerkMiddleware() export const config = { ... } -
更新 Next.js 版本:
pnpm add next@latest -
确认环境变量仍位于
.env.local中(无需更改) -
测试迁移:
pnpm dev
迁移故障排查
- 如果路由未受保护,请确认
proxy.ts位于正确位置(项目根目录或/src) - 检查
.env.local是否包含所有必需的 Clerk 密钥 - 如果中间件更改未生效,请清除
.next缓存:rm -rf .next && pnpm dev - 确认 Next.js 版本为 16.0 或更高:
pnpm list next
使用 Clerk 构建 MCP 服务
完整的 MCP 服务集成说明请参阅 CLERK_MCP_SERVER_SETUP.md。
MCP 快速设置概要
-
安装 MCP 依赖:
pnpm add @vercel/mcp-adapter @clerk/mcp-tools -
在
app/[transport]/route.ts创建 MCP 路由:import { verifyClerkToken } from '@clerk/mcp-tools/next' import { createMcpHandler, withMcpAuth } from '@vercel/mcp-adapter' import { auth, clerkClient } from '@clerk/nextjs/server' const clerk = await clerkClient() const handler = createMcpHandler((server) => { server.tool( 'get-clerk-user-data', 'Gets data about the Clerk user that authorized this request', {}, async (_, { authInfo }) => { const userId = authInfo!.extra!.userId! as string const userData = await clerk.users.getUser(userId) return { content: [{ type: 'text', text: JSON.stringify(userData) }], } }, ) }) const authHandler = withMcpAuth( handler, async (_, token) => { const clerkAuth = await auth({ acceptsToken: 'oauth_token' }) return verifyClerkToken(clerkAuth, token) }, { required: true, resourceMetadataPath: '/.well-known/oauth-protected-resource/mcp', }, ) export { authHandler as GET, authHandler as POST } -
公开 OAuth 元数据端点(完整设置请参阅参考资料)
-
更新 proxy.ts,排除
.well-known端点:import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server' const isPublicRoute = createRouteMatcher([ '/.well-known/oauth-authorization-server(.*)', '/.well-known/oauth-protected-resource(.*)', ]) export default clerkMiddleware(async (auth, req) => { if (isPublicRoute(req)) return await auth.protect() }) -
在 Clerk 控制面板中启用动态客户端注册
最佳实践
1. 环境变量管理
- 开发时始终使用
.env.local(切勿提交敏感密钥) - 在应用启动时验证环境变量
- 仅对可安全公开的非敏感密钥使用
NEXT_PUBLIC_前缀 - 在生产环境中,将环境变量设置在部署平台(Vercel 等)中
2. 路由保护策略
// Option A: Protect all routes
export default clerkMiddleware(async (auth, req) => {
await auth.protect()
})
// Option B: Protect specific routes
import { createRouteMatcher } from '@clerk/nextjs/server'
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/api/user(.*)'])
export default clerkMiddleware(async (auth, req) => {
if (isProtectedRoute(req)) {
await auth.protect()
}
})
// Option C: Public routes with opt-in protection
const isPublicRoute = createRouteMatcher(['/sign-in(.*)', '/sign-up(.*)'])
export default clerkMiddleware(async (auth, req) => {
if (!isPublicRoute(req)) {
await auth.protect()
}
})
3. MCP 服务安全
- 在 Clerk Dashboard 中启用 Dynamic Client Registration
- 保持
.well-known端点公开,但通过 OAuth 保护所有 MCP 工具 - 在
auth()中使用acceptsToken: 'oauth_token',要求使用机器令牌 - 公开测试期间 OAuth 令牌免费(定价待定)
- 在公开用户数据前,务必使用
verifyClerkToken()验证令牌
4. 性能与缓存
- 使用
clerkClient()在服务端查询用户(自动缓存) - 利用 React Server Components 安全地访问用户数据
- 尽可能缓存用户数据,以减少 API 调用
- 仅在客户端组件(
'use client')中使用@clerk/nextjs钩子
5. 生产环境部署
- 在部署平台中设置所有环境变量
- 使用 Clerk 的生产实例密钥(而非开发密钥)
- 在部署到生产环境前,先在预发布环境中测试身份验证流程
- 在 Clerk Dashboard 中监控身份验证错误
- 保持
@clerk/nextjs更新:pnpm update @clerk/nextjs
故障排除
问题与解决方案
| 问题 | 解决方案 |
|---|---|
| "Missing environment variables" | 确保 .env.local 包含 NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY 和 CLERK_SECRET_KEY |
| 中间件未保护路由 | 确认 proxy.ts 位于根目录或 /src 目录,而非 app/ 中 |
| 登录/注册页面无法正常工作 | 检查 .env.local 中的 NEXT_PUBLIC_CLERK_SIGN_IN_URL 和 NEXT_PUBLIC_CLERK_SIGN_UP_URL |
| 用户数据返回 null | 确保用户已通过身份验证:调用 getUser() 前检查 userId 不为 null |
| MCP 服务 OAuth 失败 | 在 Clerk Dashboard 的 OAuth Applications 中启用 Dynamic Client Registration |
| 更改未生效 | 清除 .next 缓存:运行 rm -rf .next 并重启 pnpm dev |
| 无法识别 "proxy.ts" | 确认 Next.js 版本为 16.0 或更高:pnpm list next |
Next.js 16 常见注意事项
- 文件命名:Next.js 16 必须使用
proxy.ts(而非middleware.ts) - 位置:将
proxy.ts放在项目根目录或/src目录中,切勿放在app/中 - 重新导出:必须从
proxy.ts导出配置对象,匹配器才能正常工作 - 异步操作:
clerkMiddleware()支持异步;使用await auth.protect()保护路由
调试模式
启用调试日志:
// proxy.ts
import { clerkMiddleware } from '@clerk/nextjs/server'
export default clerkMiddleware((auth, req) => {
if (process.env.DEBUG_CLERK) {
console.log('Request URL:', req.nextUrl.pathname)
console.log('User ID:', auth.sessionClaims?.sub)
}
})
启用调试运行:
DEBUG_CLERK=1 pnpm dev
相关技能
- mcp-server-skills:使用 Vercel 适配器的通用 MCP 服务模式
- nextjs16-skills:Next.js 16 功能、重大变更和最佳实践
- authjs-skills:使用 Auth.js(Auth0、GitHub 等)的替代身份验证方案