mcpField
C
clerk-nextjs-skills

clerk-nextjs-skills

github.com/gocallum開発23436 回インストール40 週間前に更新
リポジトリ

clerk-nextjs-skills について

Next.js 開発者向けの Clerk 統合スキルで、認証、ルート保護、ユーザーデータの取得、Next.js バージョン間の移行を解説します。Vercel アダプターと Clerk ツールを使った OAuth 検証付き MCP サーバーの構築方法も扱います。

主な機能

  1. 01Clerk 認証の設定
  2. 02Next.js ルートの保護
  3. 03クライアントとサーバーでのユーザーデータ取得
  4. 04middleware.ts から proxy.ts への移行
  5. 05OAuth 検証付き MCP サーバーの設定

活用シーン

  1. 01Next.js アプリへのサインインと登録の追加
  2. 02選択したルートへの認証必須化
  3. 03Next.js 15 プロジェクトの 16 への移行
  4. 04MCP ツール向け 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.md
QUICK_REFERENCE.md
README.md
references/
CLERK_ENV_SETUP.md
CLERK_MCP_SERVER_SETUP.md
EXAMPLES.md
PROXY_MIGRATION.md
scripts/
setup-clerk-nextjs.sh

詳細

リンク

クイックスタート

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 にアクセスし、「Sign Up」をクリックして最初のユーザーを作成します。

主要な概念

proxy.ts と middleware.ts の違い
  • Next.js 16(App Router):Clerk ミドルウェアには proxy.ts を使用します
  • 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)への移行

移行手順
  1. ファイル名を変更する:middleware.ts から proxy.ts に変更します(場所はルートまたは /src のままです)

  2. コードはそのままにする — 機能上の変更は不要です:

    // 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 = { ... }
    
  3. Next.js のバージョンを更新する:

    pnpm add next@latest
    
  4. 環境変数を確認する:引き続き .env.local に設定されていることを確認します(変更は不要です)

  5. 移行をテストする:

    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 セットアップの概要
  1. MCP の依存関係をインストールする:

    pnpm add @vercel/mcp-adapter @clerk/mcp-tools
    
  2. MCP ルートを作成する:app/[transport]/route.ts に作成します。

    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 }
    
  3. OAuth メタデータのエンドポイントを公開する(完全なセットアップについてはリファレンスを参照してください)

  4. 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()
    })
    
  5. Clerk ダッシュボード で Dynamic Client Registration を有効にする

ベストプラクティス

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 で動的クライアント登録を有効にします
  • .well-known エンドポイントは公開したまま、すべての MCP ツールを OAuth で保護します
  • マシントークンを必須にするには、auth() で acceptsToken: 'oauth_token' を使用します
  • パブリックベータ期間中、OAuth トークンは無料です(料金は未定)
  • ユーザーデータを公開する前に、必ず verifyClerkToken() でトークンを検証します
4. パフォーマンスとキャッシュ
  • サーバー側のユーザークエリには clerkClient() を使用します(自動的にキャッシュされます)
  • React Server Components を活用して、ユーザーデータに安全にアクセスします
  • API 呼び出しを減らすため、可能な場合はユーザーデータをキャッシュします
  • @clerk/nextjs のフックはクライアントコンポーネント('use client')でのみ使用します
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 が app/ ではなく、ルートまたは /src ディレクトリにあることを確認します
サインイン/サインアップページが機能しない.env.local の NEXT_PUBLIC_CLERK_SIGN_IN_URL と NEXT_PUBLIC_CLERK_SIGN_UP_URL を確認します
ユーザーデータが null を返すユーザーが認証済みであることを確認します:getUser() を呼び出す前に userId が null でないことを確認します
MCP サーバーの OAuth が失敗するClerk Dashboard の OAuth Applications で動的クライアント登録を有効にします
変更が反映されない.next キャッシュをクリアします:rm -rf .next を実行してから pnpm dev を再起動します
"proxy.ts" が認識されないNext.js のバージョンが 16.0 以上であることを確認します:pnpm list next
Next.js 16 でよくある注意点
  • ファイル名:Next.js 16 では middleware.ts ではなく、proxy.ts にする必要があります
  • 配置場所:proxy.ts はプロジェクトのルートまたは /src ディレクトリに配置します。app/ には配置しないでください
  • 再エクスポート:matcher を機能させるには、設定オブジェクトを 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 など)を使用した代替の認証方法

リソース

コメント