К основному содержанию
скилл CX Codex

clerk-authentication — скилл для Claude Code: авторизация Clerk

Правила подключения Clerk в Next.js: middleware, хуки, защита серверных действий и маршрутов API. Пригодится, когда проект уже на Clerk и нужен порядок в проверках доступа.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add Mindrally/skills --skill clerk-authentication -a claude-code
Открыть на GitHub

Что делает clerk-authentication

Скилл задаёт агенту рамку при работе с Clerk в Next.js. Он требует проверять авторизацию в каждой точке доступа к данным, а не только в middleware, и защищать серверные действия по отдельности. Плюс опираться на встроенные механизмы Clerk — HttpOnly cookies и защиту от CSRF.

Внутри — готовые шаблоны: ClerkProvider в app/layout.tsx (в том числе с кастомной темой через @clerk/themes), clerkMiddleware с createRouteMatcher для защищённых и публичных маршрутов, проверка роли через sessionClaims?.metadata?.role. Отдельно разобраны auth() и currentUser() в серверных компонентах, хуки useUser и useAuth в клиентских, а также getToken() для запросов к API с заголовком Authorization.

Заранее понадобится пакет @clerk/nextjs и переменные окружения NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY и CLERK_SECRET_KEY. Middleware с auth.protect() не спасёт серверное действие, если в нём нет собственной проверки userId — на этом легко оставить дыру, поэтому скилл и настаивает на defense-in-depth.

Какие задачи решает

  • закрыть дашборд и админку от неавторизованных
  • проверить роль пользователя до отдачи админского маршрута
  • защитить серверное действие от вызова без сессии
  • получить свежий токен для запроса к защищённому API
  • настроить редиректы после входа и регистрации

Примеры запросов агенту

  • Добавь Clerk в Next.js по скиллу clerk-authentication: провайдер в layout и middleware с защищёнными маршрутами
  • Проверь по скиллу clerk-authentication, что все server actions защищены через auth()
  • Настрой роли для /admin по скиллу clerk-authentication

Как установить clerk-authentication

1Через Skills CLI (Vercel)

npx skills add Mindrally/skills --skill clerk-authentication -a claude-code

2Вручную: положить файлы

~/.claude/skills/clerk-authentication/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/clerk-authentication/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора168

remix Скилл для ИИ-агента, который подсказывает, как писать Remix-приложения на TypeScript: загрузка данных, мутации и вложенные маршруты. CX Codex +1 686установок salesforce-dx Скилл задаёт агенту правила разработки на Salesforce DX: Apex, триггеры, LWC, scratch orgs и выкладка через SFDX CLI. CX Codex +1 688установок micronaut Задаёт агенту конвенции Micronaut: DI на этапе компиляции, нативные сборки GraalVM, реактивные сервисы. Пригодится, когда проект на Java и хочется, чтобы кодогенерация шла по фреймворку, а не наугад. CX Codex +1 687установок julia Задаёт агенту стиль кода на Julia: мультиметоды, типы, тесты и оптимизацию производительности. Пригодится, если пишете научные расчёты или численные библиотеки. CX Codex +1 687установок nx Скилл задаёт агенту правила работы с Nx: структура apps и libs, теги, границы модулей, генераторы и кэш. Пригодится, если проект уже собран на Nx. CX Codex +1 682установок langchain-development Задаёт агенту правила разработки на LangChain и LangGraph: композиция цепочек, агенты, память, RAG. Пригодится, когда проект на Python растёт и код надо держать в одном стиле. CX Codex +1 681установок apollo-graphql Скилл задаёт агенту правила работы с Apollo Client: запросы, мутации, фрагменты, кэш и оптимистичные обновления в React-проектах на GraphQL. CX Codex +1 677установок monorepo-tamagui Задаёт агенту правила разработки кросс-платформенного монорепо на Tamagui, Turbo, Next.js, Expo и Supabase. Пригодится, когда в одном репозитории живут веб и мобильное приложение. CX Codex +1 677установок

Похожие

clerk clerk Разбирает запрос про Clerk и отправляет к нужному скиллу: настройка, CLI, паттерны фреймворков, биллинг, вебхуки. CX Codex +1 30 000установок clerk-nextjs-skills gocallum Подключает аутентификацию Clerk в Next.js 16 с App Router: proxy.ts, переменные окружения, защита маршрутов и MCP-сервер. CX Codex +1 436установок nextjs-authentication giuseppe-trisciuoglio Скилл даёт готовые шаблоны аутентификации для Next.js 15+ App Router на Auth.js 5: провайдеры, защита маршрутов, сессии и роли. CX Codex +1 3 800установок safe-action-better-auth next-safe-action Скилл подключает Better Auth к next-safe-action: middleware сам достаёт сессию, режет неавторизованные запросы и отдаёт типизированный контекст. CX Codex +1 477установок clerk-setup clerk Настраивает аутентификацию Clerk через официальный CLI или создаёт новый проект с готовой авторизацией. Помогает подключить провайдера без ручной правки конфигов. CX Codex +1 56 600установок better-auth-authentication bobmatnyc Скилл для TypeScript-приложений: помогает настроить вход по email и паролю, социальные провайдеры и проверку почты. CX Codex +1 389установок

Рядом в теме «Безопасность»

Всё по теме «Безопасность» →

Вопросы о clerk-authentication

Как установить clerk-authentication в Claude?

Выполните npx skills add Mindrally/skills --skill clerk-authentication -a claude-code. Скилл появится в ~/.claude/skills/clerk-authentication/SKILL.md.

Что делает clerk-authentication?

Даёт агенту правила реализации авторизации Clerk в Next.js: middleware, серверные и клиентские компоненты, защита API-маршрутов и серверных действий.

Какие переменные окружения нужны?

Обязательны NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY и CLERK_SECRET_KEY. URL страниц входа, регистрации и редиректов после них задаются отдельно.

Исходный текст

SKILL.md · Apache-2.0
---
name: clerk-authentication
description: Guidelines for implementing Clerk authentication in Next.js applications with middleware, hooks, and security best practices
metadata:
  maintainer: Mindrally
  source: https://github.com/Mindrally/skills
---

# Clerk Authentication

You are an expert in Clerk authentication implementation for Next.js applications. Follow these guidelines when integrating Clerk.

## Core Principles

- Implement defense-in-depth with multiple authentication layers
- Verify authentication at every data access point, not just middleware
- Protect server actions individually
- Use Clerk's built-in security features (HttpOnly cookies, CSRF protection)

## Installation and Setup

```bash
npm install @clerk/nextjs
```

### Environment Variables

```bash
# Required
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...

# Optional: Custom URLs
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
```

## Provider Setup

### App Router (app/layout.tsx)

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

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

### With Custom Appearance

```typescript
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 Configuration

### Basic Middleware (middleware.ts)

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

// Define protected routes
const isProtectedRoute = createRouteMatcher([
  '/dashboard(.*)',
  '/api/protected(.*)',
  '/settings(.*)',
]);

// Define public routes (optional, for clarity)
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: [
    // Skip Next.js internals and static files
    '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
    // Always run for API routes
    '/(api|trpc)(.*)',
  ],
};
```

### Advanced Middleware with Role-Based Access

```typescript
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();

  // Admin routes require admin role
  if (isAdminRoute(req)) {
    if (!userId || sessionClaims?.metadata?.role !== 'admin') {
      return new Response('Forbidden', { status: 403 });
    }
  }

  // Protected routes require authentication
  if (isProtectedRoute(req)) {
    await auth.protect();
  }
});
```

## Authentication in Server Components

### Using auth()

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

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

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

  // Fetch user-specific data
  const data = await fetchUserData(userId);

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

### Using currentUser()

```typescript
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>
  );
}
```

## Authentication in Client Components

### useUser Hook

```typescript
'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 Hook

```typescript
'use client';

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

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

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

    // Get a fresh token for API calls
    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>;
}
```

## Server Actions Protection

Always protect server actions individually:

```typescript
'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;

  // Create post with user ID
  const post = await db.post.create({
    data: {
      title,
      content,
      authorId: userId,
    },
  });

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

### With Role Validation

```typescript
'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 Route Protection

### Route Handlers (App Router)

```typescript
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();
  // Process request...

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

## JWT Verification for External APIs

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

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

  // Get JWT for external API
  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());
}
```

## Organization Support

```typescript
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');
  }

  // Check organization role
  if (orgRole !== 'org:admin') {
    throw new Error('Admin access required');
  }

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

## Custom Session Claims

### Configure in Clerk Dashboard

Add custom claims via JWT Templates, then access them:

```typescript
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 Components

### Pre-built Components

```typescript
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>
  );
}

// Dedicated sign-in page
export default function SignInPage() {
  return (
    <div className="flex justify-center items-center min-h-screen">
      <SignIn />
    </div>
  );
}
```

## Security Best Practices

### 1. Defense in Depth

```typescript
// Layer 1: Middleware
export default clerkMiddleware(async (auth, req) => {
  if (isProtectedRoute(req)) {
    await auth.protect();
  }
});

// Layer 2: Server Component
export default async function Page() {
  const { userId } = await auth();
  if (!userId) redirect('/sign-in');
  // ...
}

// Layer 3: Data Access
async function fetchUserData(userId: string) {
  const { userId: currentUserId } = await auth();
  if (currentUserId !== userId) throw new Error('Forbidden');
  // ...
}
```

### 2. Protect All Server Actions

```typescript
// Every server action should verify auth independently
'use server';

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

### 3. Avoid Client-Side Only Protection

```typescript
// BAD: Client-side only check
'use client';
export function SecretComponent() {
  const { isSignedIn } = useAuth();
  if (!isSignedIn) return null;
  return <div>Secret Data</div>; // Data still sent to client!
}

// GOOD: Server-side protection
export default async function SecretPage() {
  const { userId } = await auth();
  if (!userId) redirect('/sign-in');
  const data = await fetchSecretData(userId);
  return <SecretComponent data={data} />;
}
```

## Error Handling

```typescript
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;
  }
}
```

## Testing

```typescript
// Mock Clerk for testing
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);
  });
});
```

## Common Anti-Patterns to Avoid

1. Relying solely on middleware for protection
2. Not protecting server actions individually
3. Using client-side auth checks for sensitive data
4. Exposing user data without ownership verification
5. Not validating organization membership for org-scoped resources
6. Hardcoding role checks instead of using Clerk's RBAC
7. Not handling loading states in client components

© Mindrally · Apache-2.0 · Mindrally/skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой