Agent Skills by ALSEL
Anthropic Claudeセキュリティ⭐ リポ 0品質スコア 50/100

clerk-authentication

Next.jsアプリケーションにClerk認証を実装するためのガイドラインです。ミドルウェアの設定、各種フックの活用、セキュリティのベストプラクティスまでを網羅しており、認証機能を安全かつ効率的に組み込みたい場合に活用できます。

description の原文を見る

Guidelines for implementing Clerk authentication in Next.js applications with middleware, hooks, and security best practices

SKILL.md 本文

Clerk認証

Next.jsアプリケーションにおけるClerk認証実装のエキスパートです。Clerkを統合する際は、以下のガイドラインに従ってください。

コア原則

  • 複数の認証レイヤーを備えた多層防御を実装する
  • 単にミドルウェアだけでなく、すべてのデータアクセスポイントで認証を検証する
  • サーバーアクションを個別に保護する
  • Clerkの組み込みセキュリティ機能(HttpOnlyクッキー、CSRF保護)を利用する

インストールと設定

npm install @clerk/nextjs

環境変数

# 必須
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...

# オプション: カスタムURL
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard

プロバイダーの設定

App Router (app/layout.tsx)

import { ClerkProvider } from '@clerk/nextjs';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <ClerkProvider>
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

カスタム外観付き

import { ClerkProvider } from '@clerk/nextjs';
import { dark } from '@clerk/themes';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <ClerkProvider
      appearance={{
        baseTheme: dark,
        variables: {
          colorPrimary: '#3b82f6',
        },
        elements: {
          formButtonPrimary: 'bg-blue-500 hover:bg-blue-600',
        },
      }}
    >
      <html lang="en">
        <body>{children}</body>
      </html>
    </ClerkProvider>
  );
}

ミドルウェア設定

基本的なミドルウェア (middleware.ts)

import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

// 保護されたルートを定義
const isProtectedRoute = createRouteMatcher([
  '/dashboard(.*)',
  '/api/protected(.*)',
  '/settings(.*)',
]);

// パブリックルートを定義(オプション、明確性のため)
const isPublicRoute = createRouteMatcher([
  '/',
  '/sign-in(.*)',
  '/sign-up(.*)',
  '/api/public(.*)',
]);

export default clerkMiddleware(async (auth, req) => {
  if (isProtectedRoute(req)) {
    await auth.protect();
  }
});

export const config = {
  matcher: [
    // Next.js内部と静的ファイルをスキップ
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // APIルートに対しては常に実行
    '/(api|trpc)(.*)',
  ],
};

ロールベースアクセス制御を備えた高度なミドルウェア

import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';

const isAdminRoute = createRouteMatcher(['/admin(.*)']);
const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/api/protected(.*)']);

export default clerkMiddleware(async (auth, req) => {
  const { userId, sessionClaims } = await auth();

  // 管理者ルートは管理者ロールが必須
  if (isAdminRoute(req)) {
    if (!userId || sessionClaims?.metadata?.role !== 'admin') {
      return new Response('Forbidden', { status: 403 });
    }
  }

  // 保護されたルートは認証が必須
  if (isProtectedRoute(req)) {
    await auth.protect();
  }
});

サーバーコンポーネントでの認証

auth()を使用する

import { auth } from '@clerk/nextjs/server';

export default async function DashboardPage() {
  const { userId } = await auth();

  if (!userId) {
    redirect('/sign-in');
  }

  // ユーザー固有のデータを取得
  const data = await fetchUserData(userId);

  return <Dashboard data={data} />;
}

currentUser()を使用する

import { currentUser } from '@clerk/nextjs/server';

export default async function ProfilePage() {
  const user = await currentUser();

  if (!user) {
    redirect('/sign-in');
  }

  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <p>Email: {user.emailAddresses[0]?.emailAddress}</p>
    </div>
  );
}

クライアントコンポーネントでの認証

useUserフック

'use client';

import { useUser } from '@clerk/nextjs';

export function UserProfile() {
  const { isLoaded, isSignedIn, user } = useUser();

  if (!isLoaded) {
    return <Skeleton />;
  }

  if (!isSignedIn) {
    return <SignInPrompt />;
  }

  return (
    <div>
      <img src={user.imageUrl} alt={user.fullName ?? 'User'} />
      <p>{user.fullName}</p>
    </div>
  );
}

useAuthフック

'use client';

import { useAuth } from '@clerk/nextjs';

export function ProtectedAction() {
  const { isLoaded, userId, getToken } = useAuth();

  async function handleAction() {
    if (!userId) return;

    // APIコール用に新しいトークンを取得
    const token = await getToken();

    const response = await fetch('/api/protected', {
      headers: {
        Authorization: `Bearer ${token}`,
      },
    });
  }

  if (!isLoaded || !userId) {
    return null;
  }

  return <button onClick={handleAction}>Perform Action</button>;
}

サーバーアクションの保護

常にサーバーアクションを個別に保護してください:

'use server';

import { auth } from '@clerk/nextjs/server';

export async function createPost(formData: FormData) {
  const { userId } = await auth();

  if (!userId) {
    throw new Error('Unauthorized');
  }

  const title = formData.get('title') as string;
  const content = formData.get('content') as string;

  // ユーザーIDを含めてポストを作成
  const post = await db.post.create({
    data: {
      title,
      content,
      authorId: userId,
    },
  });

  revalidatePath('/posts');
  return post;
}

ロール検証付き

'use server';

import { auth } from '@clerk/nextjs/server';

export async function deleteUser(userId: string) {
  const { userId: currentUserId, sessionClaims } = await auth();

  if (!currentUserId) {
    throw new Error('Unauthorized');
  }

  if (sessionClaims?.metadata?.role !== 'admin') {
    throw new Error('Forbidden: Admin access required');
  }

  await db.user.delete({ where: { id: userId } });
  revalidatePath('/admin/users');
}

APIルートの保護

ルートハンドラー (App Router)

import { auth } from '@clerk/nextjs/server';
import { NextResponse } from 'next/server';

export async function GET() {
  const { userId } = await auth();

  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const data = await fetchUserData(userId);
  return NextResponse.json(data);
}

export async function POST(request: Request) {
  const { userId } = await auth();

  if (!userId) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const body = await request.json();
  // リクエストを処理...

  return NextResponse.json({ success: true });
}

外部APIのJWT検証

import { auth } from '@clerk/nextjs/server';

export async function GET() {
  const { getToken } = await auth();

  // 外部API用のJWTを取得
  const token = await getToken({ template: 'external-api' });

  const response = await fetch('https://external-api.com/data', {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });

  return Response.json(await response.json());
}

組織サポート

import { auth } from '@clerk/nextjs/server';

export async function getOrganizationData() {
  const { userId, orgId, orgRole } = await auth();

  if (!userId || !orgId) {
    throw new Error('Must be in an organization');
  }

  // 組織ロールを確認
  if (orgRole !== 'org:admin') {
    throw new Error('Admin access required');
  }

  return await db.organization.findUnique({
    where: { clerkOrgId: orgId },
  });
}

カスタムセッションクレーム

Clerkダッシュボードで設定

JWTテンプレート経由でカスタムクレームを追加してからアクセスします:

import { auth } from '@clerk/nextjs/server';

export async function checkSubscription() {
  const { sessionClaims } = await auth();

  const plan = sessionClaims?.metadata?.subscriptionPlan;

  if (plan !== 'pro') {
    throw new Error('Pro subscription required');
  }
}

UIコンポーネント

プリビルトコンポーネント

import {
  SignIn,
  SignUp,
  SignOutButton,
  UserButton,
  SignedIn,
  SignedOut,
} from '@clerk/nextjs';

export function Header() {
  return (
    <header>
      <SignedIn>
        <UserButton afterSignOutUrl="/" />
      </SignedIn>
      <SignedOut>
        <SignInButton mode="modal" />
      </SignedOut>
    </header>
  );
}

// 専用サインインページ
export default function SignInPage() {
  return (
    <div className="flex justify-center items-center min-h-screen">
      <SignIn />
    </div>
  );
}

セキュリティのベストプラクティス

1. 多層防御

// レイヤー1: ミドルウェア
export default clerkMiddleware(async (auth, req) => {
  if (isProtectedRoute(req)) {
    await auth.protect();
  }
});

// レイヤー2: サーバーコンポーネント
export default async function Page() {
  const { userId } = await auth();
  if (!userId) redirect('/sign-in');
  // ...
}

// レイヤー3: データアクセス
async function fetchUserData(userId: string) {
  const { userId: currentUserId } = await auth();
  if (currentUserId !== userId) throw new Error('Forbidden');
  // ...
}

2. すべてのサーバーアクションを保護

// すべてのサーバーアクションは独立して認証を検証する必要があります
'use server';

export async function sensitiveAction() {
  const { userId } = await auth();
  if (!userId) throw new Error('Unauthorized');
  // ...
}

3. クライアント側のみの保護を回避

// 不正: クライアント側のみのチェック
'use client';
export function SecretComponent() {
  const { isSignedIn } = useAuth();
  if (!isSignedIn) return null;
  return <div>Secret Data</div>; // データはまだクライアントに送られます!
}

// 正しい: サーバー側の保護
export default async function SecretPage() {
  const { userId } = await auth();
  if (!userId) redirect('/sign-in');
  const data = await fetchSecretData(userId);
  return <SecretComponent data={data} />;
}

エラーハンドリング

import { auth } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';

export default async function ProtectedPage() {
  try {
    const { userId } = await auth();

    if (!userId) {
      redirect('/sign-in');
    }

    const data = await fetchUserData(userId);
    return <Dashboard data={data} />;
  } catch (error) {
    if (error instanceof AuthenticationError) {
      redirect('/sign-in');
    }
    throw error;
  }
}

テスト

// テスト用にClerkをモック
import { auth } from '@clerk/nextjs/server';

jest.mock('@clerk/nextjs/server', () => ({
  auth: jest.fn(),
}));

describe('Protected API', () => {
  it('returns 401 for unauthenticated requests', async () => {
    (auth as jest.Mock).mockResolvedValue({ userId: null });

    const response = await GET();
    expect(response.status).toBe(401);
  });

  it('returns data for authenticated requests', async () => {
    (auth as jest.Mock).mockResolvedValue({ userId: 'user_123' });

    const response = await GET();
    expect(response.status).toBe(200);
  });
});

避けるべき一般的なアンチパターン

  1. ミドルウェアのみに依存した保護
  2. サーバーアクションを個別に保護しない
  3. 機密データに対してクライアント側の認証チェックを使用する
  4. 所有権検証なしでユーザーデータを公開する
  5. 組織スコープのリソースに対して組織メンバーシップを検証しない
  6. Clerkのロールベースアクセス制御の代わりにロールチェックをハードコードする
  7. クライアントコンポーネントのローディング状態を処理しない

ライセンス: Apache-2.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
mindrally
リポジトリ
mindrally/skills
ライセンス
Apache-2.0
最終更新
不明

Source: https://github.com/mindrally/skills / ライセンス: Apache-2.0

関連スキル

Anthropic Claudeセキュリティ⭐ リポ 8,981

secure-code-guardian

認証・認可の実装、ユーザー入力の保護、OWASP Top 10の脆弱性対策が必要な場合に使用します。bcrypt/argon2によるパスワードハッシング、パラメータ化ステートメントによるSQLインジェクション対策、CORS/CSPヘッダーの設定、Zodによる入力検証、JWTトークンの構築などのカスタムセキュリティ実装に対応します。認証、認可、入力検証、暗号化、OWASP Top 10対策、セッション管理、セキュリティ強化全般で活用できます。ただし、構築済みのOAuth/SSO統合や単独のセキュリティ監査が必要な場合は、より特化したスキルの検討をお勧めします。

by Jeffallan
汎用セキュリティ⭐ リポ 1,982

claude-authenticity

APIエンドポイントが本物のClaudeによって支えられているか(ラッパーやプロキシ、偽装ではないか)を、claude-verifyプロジェクトを模した9つの重み付きルールベースチェックで検証できます。また、Claudeの正体を上書きしているプロバイダーから注入されたシステムプロンプトも抽出します。完全に自己完結しており、httpx以外の追加パッケージは不要です。Claude APIキーまたはエンドポイントを検証したい場合、サードパーティのClaudeサービスが本物か確認したい場合、APIプロバイダーのClaude正当性を監査したい場合、複数モデルを並行してテストしたい場合、またはプロバイダーが注入したシステムプロンプトを特定したい場合に使用できます。

by LeoYeAI
Anthropic Claudeセキュリティ⭐ リポ 2,159

anth-security-basics

Anthropic Claude APIのセキュリティベストプラクティスを適用し、キー管理、入力値の検証、プロンプトインジェクション対策を実施します。APIキーの保護、Claudeに送信する前のユーザー入力検証、コンテンツセーフティガードレールの実装が必要な場合に活用できます。「anthropic security」「claude api key security」「secure anthropic」「prompt injection defense」といったフレーズでトリガーされます。

by jeremylongshore
汎用セキュリティ⭐ リポ 699

x-ray

x-ray.mdプレ監査レポートを生成します。概要、強化された脅威モデル(プロトコルタイプのプロファイリング、Gitの重み付け攻撃面分析、時間軸リスク分析、コンポーザビリティ依存関係マッピング)、不変条件、統合、ドキュメント品質、テスト分析、開発者・Gitの履歴をカバーしています。「x-ray」「audit readiness」「readiness report」「pre-audit report」「prep this protocol」「protocol prep」「summarize this protocol」のキーワードで実行されます。

by pashov
汎用セキュリティ⭐ リポ 677

semgrep

Semgrepスタティック分析スキャンを実行し、カスタム検出ルールを作成します。Semgrepでのコードスキャン、セキュリティ脆弱性の検出、カスタムYAMLルールの作成、または特定のバグパターンの検出が必要な場合に使用します。重要:ユーザーが「バグをスキャンしたい」「コード品質を確認したい」「脆弱性を見つけたい」「スタティック分析」「セキュリティlint」「コード監査」または「コーディング標準を適用したい」と尋ねた場合も、Semgrepという名称を明記していなくても、このスキルを使用してください。Semgrepは30以上の言語に対応したパターンベースのコードスキャンに最適なツールです。

by wimpysworld
汎用セキュリティ⭐ リポ 591

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を再度有効化します。

by yaklang
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: mindrally · mindrally/skills · ライセンス: Apache-2.0