clerk-core-workflow-b
Clerkを使用したセッション管理とミドルウェアの実装ができます。 ユーザーセッションの管理、ルート保護の設定、トークンリフレッシュロジックの実装が必要な場合に使用してください。 「clerk session」「clerk middleware」「clerk route protection」「clerk token」「clerk JWT」などのフレーズで実行されます。
description の原文を見る
Implement session management and middleware with Clerk. Use when managing user sessions, configuring route protection, or implementing token refresh logic. Trigger with phrases like "clerk session", "clerk middleware", "clerk route protection", "clerk token", "clerk JWT".
SKILL.md 本文
Clerk Core Workflow B: セッション & ミドルウェア
概要
ユーザーセッションを管理し、ミドルウェアでルートを保護し、JWTトークンを処理します。
前提条件
- Clerk SDKのインストールと設定が完了している
- 認証フローが実装されている
- Next.jsミドルウェアの理解がある
手順
ステップ1: 高度なミドルウェア設定
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'
const isPublicRoute = createRouteMatcher([
'/',
'/sign-in(.*)',
'/sign-up(.*)',
'/api/webhooks(.*)',
'/api/public(.*)'
])
const isAdminRoute = createRouteMatcher(['/admin(.*)'])
const isAPIRoute = createRouteMatcher(['/api/(.*)'])
export default clerkMiddleware(async (auth, request) => {
const { userId, orgRole, sessionClaims } = await auth()
// Allow public routes
if (isPublicRoute(request)) {
return NextResponse.next()
}
// Require authentication for all other routes
if (!userId) {
const signInUrl = new URL('/sign-in', request.url)
signInUrl.searchParams.set('redirect_url', request.url)
return NextResponse.redirect(signInUrl)
}
// Admin route protection
if (isAdminRoute(request)) {
if (orgRole !== 'org:admin') {
return NextResponse.redirect(new URL('/unauthorized', request.url))
}
}
// Add custom headers for API routes
if (isAPIRoute(request)) {
const response = NextResponse.next()
response.headers.set('x-user-id', userId)
return response
}
return NextResponse.next()
})
export const config = {
matcher: ['/((?!_next|[^?]*\\.(?:html?|css|js|jpe?g|webp|png|gif|svg|ttf|woff2?|ico)).*)', '/']
}
ステップ2: セッション管理
'use client'
import { useSession, useAuth } from '@clerk/nextjs'
export function SessionManager() {
const { session, isLoaded } = useSession()
const { signOut } = useAuth()
if (!isLoaded) return <div>Loading session...</div>
if (!session) return <div>No active session</div>
const handleSignOutAll = async () => {
// Sign out from all devices
await signOut({ sessionId: 'all' })
}
const handleSignOutCurrent = async () => {
// Sign out from current session only
await signOut()
}
return (
<div>
<h2>Session Info</h2>
<p>Session ID: {session.id}</p>
<p>Created: {new Date(session.createdAt).toLocaleString()}</p>
<p>Last Active: {new Date(session.lastActiveAt).toLocaleString()}</p>
<p>Expires: {new Date(session.expireAt).toLocaleString()}</p>
<div className="space-x-2">
<button onClick={handleSignOutCurrent}>Sign Out</button>
<button onClick={handleSignOutAll}>Sign Out All Devices</button>
</div>
</div>
)
}
ステップ3: トークン管理
'use client'
import { useAuth } from '@clerk/nextjs'
export function useClerkToken() {
const { getToken, isLoaded, isSignedIn } = useAuth()
const fetchWithAuth = async (url: string, options: RequestInit = {}) => {
if (!isLoaded || !isSignedIn) {
throw new Error('Not authenticated')
}
const token = await getToken()
return fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
})
}
const fetchWithCustomTemplate = async (url: string, template: string) => {
const token = await getToken({ template })
return fetch(url, {
headers: {
Authorization: `Bearer ${token}`
}
})
}
return { fetchWithAuth, fetchWithCustomTemplate, getToken }
}
ステップ4: サーバーサイドセッション検証
// app/api/protected/route.ts
import { auth } from '@clerk/nextjs/server'
import { headers } from 'next/headers'
export async function GET() {
const { userId, sessionId, sessionClaims } = await auth()
if (!userId) {
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
// Access session claims
const email = sessionClaims?.email as string
const role = sessionClaims?.metadata?.role as string
// Validate session freshness
const sessionAge = Date.now() - (sessionClaims?.iat ?? 0) * 1000
const maxAge = 60 * 60 * 1000 // 1 hour
if (sessionAge > maxAge) {
return Response.json({ error: 'Session expired' }, { status: 401 })
}
return Response.json({
userId,
sessionId,
email,
role
})
}
ステップ5: マルチセッション対応
'use client'
import { useSessionList, useSession } from '@clerk/nextjs'
export function SessionList() {
const { sessions, isLoaded, setActive } = useSessionList()
const { session: currentSession } = useSession()
if (!isLoaded) return <div>Loading sessions...</div>
return (
<div>
<h2>Active Sessions</h2>
<ul>
{sessions?.map((session) => (
<li key={session.id}>
<span>{session.id}</span>
<span>{session.id === currentSession?.id ? ' (current)' : ''}</span>
<button onClick={() => setActive({ session: session.id })}>
Switch
</button>
<button onClick={() => session.remove()}>
Revoke
</button>
</li>
))}
</ul>
</div>
)
}
出力
- ミドルウェアで保護されたルート
- セッション管理UI
- トークンリフレッシュ処理
- マルチセッション対応
エラーハンドリング
| エラー | 原因 | 解決策 |
|---|---|---|
| セッションが見つからない | 期限切れまたは取り消し | サインインページにリダイレクト |
| トークン有効期限切れ | JWT有効期限超過 | getToken()で新しいトークンを取得 |
| ミドルウェアループ | マッチャーが不正確 | マッチャー正規表現が静的ファイルを除外していることを確認 |
| ヘッダーがすでに送信済み | レスポンスが既に開始 | ミドルウェアの順序を確認 |
例
レート制限ミドルウェア
import { clerkMiddleware } from '@clerk/nextjs/server'
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s')
})
export default clerkMiddleware(async (auth, request) => {
const { userId } = await auth()
if (userId) {
const { success } = await ratelimit.limit(userId)
if (!success) {
return Response.json({ error: 'Rate limited' }, { status: 429 })
}
}
})
リソース
次のステップ
clerk-common-errorsに進んで、一般的な問題のトラブルシューティングを行います。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- Brmbobo
- リポジトリ
- Brmbobo/Web2podcast
- ライセンス
- MIT
- 最終更新
- 2026/1/26
Source: https://github.com/Brmbobo/Web2podcast / ライセンス: MIT
関連スキル
secure-code-guardian
認証・認可の実装、ユーザー入力の保護、OWASP Top 10の脆弱性対策が必要な場合に使用します。bcrypt/argon2によるパスワードハッシング、パラメータ化ステートメントによるSQLインジェクション対策、CORS/CSPヘッダーの設定、Zodによる入力検証、JWTトークンの構築などのカスタムセキュリティ実装に対応します。認証、認可、入力検証、暗号化、OWASP Top 10対策、セッション管理、セキュリティ強化全般で活用できます。ただし、構築済みのOAuth/SSO統合や単独のセキュリティ監査が必要な場合は、より特化したスキルの検討をお勧めします。
claude-authenticity
APIエンドポイントが本物のClaudeによって支えられているか(ラッパーやプロキシ、偽装ではないか)を、claude-verifyプロジェクトを模した9つの重み付きルールベースチェックで検証できます。また、Claudeの正体を上書きしているプロバイダーから注入されたシステムプロンプトも抽出します。完全に自己完結しており、httpx以外の追加パッケージは不要です。Claude APIキーまたはエンドポイントを検証したい場合、サードパーティのClaudeサービスが本物か確認したい場合、APIプロバイダーのClaude正当性を監査したい場合、複数モデルを並行してテストしたい場合、またはプロバイダーが注入したシステムプロンプトを特定したい場合に使用できます。
anth-security-basics
Anthropic Claude APIのセキュリティベストプラクティスを適用し、キー管理、入力値の検証、プロンプトインジェクション対策を実施します。APIキーの保護、Claudeに送信する前のユーザー入力検証、コンテンツセーフティガードレールの実装が必要な場合に活用できます。「anthropic security」「claude api key security」「secure anthropic」「prompt injection defense」といったフレーズでトリガーされます。
x-ray
x-ray.mdプレ監査レポートを生成します。概要、強化された脅威モデル(プロトコルタイプのプロファイリング、Gitの重み付け攻撃面分析、時間軸リスク分析、コンポーザビリティ依存関係マッピング)、不変条件、統合、ドキュメント品質、テスト分析、開発者・Gitの履歴をカバーしています。「x-ray」「audit readiness」「readiness report」「pre-audit report」「prep this protocol」「protocol prep」「summarize this protocol」のキーワードで実行されます。
semgrep
Semgrepスタティック分析スキャンを実行し、カスタム検出ルールを作成します。Semgrepでのコードスキャン、セキュリティ脆弱性の検出、カスタムYAMLルールの作成、または特定のバグパターンの検出が必要な場合に使用します。重要:ユーザーが「バグをスキャンしたい」「コード品質を確認したい」「脆弱性を見つけたい」「スタティック分析」「セキュリティlint」「コード監査」または「コーディング標準を適用したい」と尋ねた場合も、Semgrepという名称を明記していなくても、このスキルを使用してください。Semgrepは30以上の言語に対応したパターンベースのコードスキャンに最適なツールです。
ghost-bits-cast-attack
Java「ゴーストビッツ」/キャストアタック プレイブック(Black Hat Asia 2026)。16ビット文字が8ビットバイトに暗黙的に縮小されるJavaサービスへの攻撃時に使用します。WAF/IDSを回避して、SQLインジェクション、デシリアライゼーション型RCE、ファイルアップロード(Webシェル)、パストトラバーサル、CRLF インジェクション、リクエストスマグリング、SMTPインジェクションを実行できます。Tomcat、Spring、Jetty、Undertow、Vert.x、Jackson、Fastjson、Apache Commons BCEL、Apache HttpClient、Angus Mail、JDK HttpServer、Lettuce、Jodd、XMLWriterに影響し、WAFバイパスにより多くの「パッチ済み」CVEを再度有効化します。