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

nextauth-authentication — скилл для Claude Code: что делает

Скилл учит агента внедрять аутентификацию через NextAuth.js (Auth.js v5) в Next.js. Помогает настроить сессии, роуты и защиту страниц.

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

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

Скилл даёт правила развёртывания Auth.js v5 на базе пакета next-auth@beta. Агент учится применять универсальную функцию auth() и настраивать переменные окружения с префиксом AUTH_, генерируя секрет AUTH_SECRET через openssl rand -base64 32.

Внутри описаны две стратегии сессий: JWT на зашифрованных cookies и хранение в базе через PrismaAdapter. Если запускать middleware на Edge, прямое обращение к базе данных сломает рантайм. По этой причине скилл задаёт сплит-конфигурацию: правила авторизации выносятся в auth.config.ts, а адаптер базы остаётся в auth.ts.

Для клиентских компонентов добавлены шаблоны провайдера SessionProvider и хука useSession. В серверных компонентах проверка сессии сводится к прямому вызову await auth().

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

  • внедрить Auth.js v5 в проект на Next.js
  • настроить провайдеры GitHub, Google или Credentials
  • разделить конфигурацию для поддержки Edge middleware с Prisma
  • закрыть маршруты в файле middleware.ts

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

  • Настрой авторизацию через NextAuth v5 с провайдерами GitHub и Google
  • Сделай middleware для защиты роутов /dashboard на базе Auth.js
  • Настрой сплит-конфигурацию auth.config.ts для работы Prisma на Edge

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

1Через Skills CLI (Vercel)

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

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

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

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

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

Вопросы о nextauth-authentication

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

Выполните в терминале команду npx skills add Mindrally/skills --skill nextauth-authentication -a claude-code.

Что делает скилл nextauth-authentication?

Он передаёт агенту правила настройки Auth.js v5: серверные вызовы auth(), настройку middleware.ts, стратегии сессий и работу с переменными окружения.

Как скилл решает конфликт базы данных и Edge middleware?

Он разделяет логику на два файла. Базовый auth.config.ts без адаптера базы подключается к middleware, а полный auth.ts с PrismaAdapter работает на обычном Node.js-сервере.

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

SKILL.md · Apache-2.0
---
name: nextauth-authentication
description: Guidelines for implementing NextAuth.js (Auth.js v5) authentication in Next.js applications with session management and security best practices
metadata:
  maintainer: Mindrally
  source: https://github.com/Mindrally/skills
---

# NextAuth Authentication

You are an expert in NextAuth.js (Auth.js v5) authentication implementation. Follow these guidelines when integrating authentication in Next.js applications.

## Core Principles

- Use Auth.js v5 patterns and the universal `auth()` function
- Implement proper session management strategy based on your needs
- Always validate sessions server-side for sensitive operations
- Configure environment variables correctly with the `AUTH_` prefix

## Installation

```bash
npm install next-auth@beta
```

## Environment Variables

```bash
# Required
AUTH_SECRET=your-32-byte-secret-here  # Generate with: openssl rand -base64 32

# Provider credentials (auto-detected if named correctly)
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret

AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret

# Optional: Custom URL (auto-detected in most environments)
AUTH_URL=https://your-domain.com
```

## Basic Configuration

### auth.ts (Root Configuration)

```typescript
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
import Credentials from 'next-auth/providers/credentials';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from '@/lib/prisma';

export const { handlers, auth, signIn, signOut } = NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [
    GitHub, // Credentials auto-detected from AUTH_GITHUB_ID/SECRET
    Google,
    Credentials({
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' },
      },
      async authorize(credentials) {
        // Validate credentials
        const user = await validateCredentials(credentials);
        if (!user) return null;
        return user;
      },
    }),
  ],
  session: {
    strategy: 'jwt', // or 'database'
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
  pages: {
    signIn: '/auth/signin',
    error: '/auth/error',
  },
  callbacks: {
    async jwt({ token, user, account }) {
      if (user) {
        token.id = user.id;
        token.role = user.role;
      }
      return token;
    },
    async session({ session, token }) {
      if (token) {
        session.user.id = token.id as string;
        session.user.role = token.role as string;
      }
      return session;
    },
    async authorized({ auth, request }) {
      const isAuthenticated = !!auth?.user;
      const isProtectedRoute = request.nextUrl.pathname.startsWith('/dashboard');

      if (isProtectedRoute && !isAuthenticated) {
        return false; // Redirect to sign-in
      }

      return true;
    },
  },
});
```

### Route Handlers (app/api/auth/[...nextauth]/route.ts)

```typescript
import { handlers } from '@/auth';

export const { GET, POST } = handlers;
```

### Middleware (middleware.ts)

```typescript
import { auth } from '@/auth';

export default auth((req) => {
  const isAuthenticated = !!req.auth;
  const isAuthPage = req.nextUrl.pathname.startsWith('/auth');
  const isProtectedRoute = req.nextUrl.pathname.startsWith('/dashboard');

  // Redirect authenticated users away from auth pages
  if (isAuthenticated && isAuthPage) {
    return Response.redirect(new URL('/dashboard', req.nextUrl));
  }

  // Redirect unauthenticated users from protected routes
  if (!isAuthenticated && isProtectedRoute) {
    return Response.redirect(new URL('/auth/signin', req.nextUrl));
  }
});

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};
```

## Session Strategies

### JWT Strategy (Default without adapter)

Best for: Serverless, Edge runtime, minimal database queries

```typescript
export const { auth } = NextAuth({
  session: {
    strategy: 'jwt',
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
});
```

Characteristics:
- Sessions stored in encrypted cookies
- No database query per request
- Cannot be invalidated before expiration
- Works with Edge middleware

### Database Strategy

Best for: Immediate session invalidation, "sign out everywhere"

```typescript
export const { auth } = NextAuth({
  adapter: PrismaAdapter(prisma),
  session: {
    strategy: 'database',
    maxAge: 30 * 24 * 60 * 60, // 30 days
  },
});
```

Characteristics:
- Sessions stored in database
- Database query on every request
- Can be invalidated immediately
- Incompatible with Edge middleware (use split config)

### Split Configuration for Edge + Database

```typescript
// auth.config.ts - Edge-compatible config
import type { NextAuthConfig } from 'next-auth';

export const authConfig: NextAuthConfig = {
  pages: {
    signIn: '/auth/signin',
  },
  callbacks: {
    authorized({ auth, request }) {
      return !!auth?.user;
    },
  },
  providers: [], // Configured in auth.ts
};

// auth.ts - Full config with adapter
import NextAuth from 'next-auth';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { authConfig } from './auth.config';

export const { handlers, auth, signIn, signOut } = NextAuth({
  ...authConfig,
  adapter: PrismaAdapter(prisma),
  providers: [GitHub, Google],
});

// middleware.ts - Uses edge-compatible config
import NextAuth from 'next-auth';
import { authConfig } from './auth.config';

export default NextAuth(authConfig).auth;
```

## Authentication in Components

### Server Components

```typescript
import { auth } from '@/auth';
import { redirect } from 'next/navigation';

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

  if (!session?.user) {
    redirect('/auth/signin');
  }

  return (
    <div>
      <h1>Welcome, {session.user.name}!</h1>
      <p>Email: {session.user.email}</p>
    </div>
  );
}
```

### Client Components

```typescript
'use client';

import { useSession } from 'next-auth/react';

export function UserProfile() {
  const { data: session, status } = useSession();

  if (status === 'loading') {
    return <Skeleton />;
  }

  if (status === 'unauthenticated') {
    return <SignInPrompt />;
  }

  return (
    <div>
      <img src={session.user.image} alt={session.user.name} />
      <p>{session.user.name}</p>
    </div>
  );
}
```

### Session Provider Setup

```typescript
// app/providers.tsx
'use client';

import { SessionProvider } from 'next-auth/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return <SessionProvider>{children}</SessionProvider>;
}

// app/layout.tsx
import { Providers } from './providers';

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

## Server Actions

```typescript
'use server';

import { auth, signIn, signOut } from '@/auth';

// Sign in action
export async function handleSignIn(provider: string) {
  await signIn(provider, { redirectTo: '/dashboard' });
}

// Sign out action
export async function handleSignOut() {
  await signOut({ redirectTo: '/' });
}

// Protected action
export async function createPost(formData: FormData) {
  const session = await auth();

  if (!session?.user) {
    throw new Error('Unauthorized');
  }

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

  await prisma.post.create({
    data: {
      title,
      authorId: session.user.id,
    },
  });

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

## API Route Protection

```typescript
import { auth } from '@/auth';
import { NextResponse } from 'next/server';

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

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

  const data = await fetchUserData(session.user.id);
  return NextResponse.json(data);
}
```

## Role-Based Access Control

### Type Extensions

```typescript
// types/next-auth.d.ts
import { DefaultSession, DefaultUser } from 'next-auth';
import { JWT, DefaultJWT } from 'next-auth/jwt';

declare module 'next-auth' {
  interface Session {
    user: {
      id: string;
      role: string;
    } & DefaultSession['user'];
  }

  interface User extends DefaultUser {
    role: string;
  }
}

declare module 'next-auth/jwt' {
  interface JWT extends DefaultJWT {
    id: string;
    role: string;
  }
}
```

### Role Check Utility

```typescript
import { auth } from '@/auth';

export async function requireRole(allowedRoles: string[]) {
  const session = await auth();

  if (!session?.user) {
    throw new Error('Unauthorized');
  }

  if (!allowedRoles.includes(session.user.role)) {
    throw new Error('Forbidden');
  }

  return session;
}

// Usage
export default async function AdminPage() {
  const session = await requireRole(['admin']);

  return <AdminDashboard user={session.user} />;
}
```

## OAuth Providers Configuration

### GitHub

```typescript
import GitHub from 'next-auth/providers/github';

GitHub({
  clientId: process.env.AUTH_GITHUB_ID,
  clientSecret: process.env.AUTH_GITHUB_SECRET,
  authorization: {
    params: {
      scope: 'read:user user:email',
    },
  },
});
```

### Google

```typescript
import Google from 'next-auth/providers/google';

Google({
  clientId: process.env.AUTH_GOOGLE_ID,
  clientSecret: process.env.AUTH_GOOGLE_SECRET,
  authorization: {
    params: {
      prompt: 'consent',
      access_type: 'offline',
      response_type: 'code',
    },
  },
});
```

### Credentials Provider

```typescript
import Credentials from 'next-auth/providers/credentials';
import bcrypt from 'bcryptjs';

Credentials({
  name: 'credentials',
  credentials: {
    email: { label: 'Email', type: 'email' },
    password: { label: 'Password', type: 'password' },
  },
  async authorize(credentials) {
    if (!credentials?.email || !credentials?.password) {
      return null;
    }

    const user = await prisma.user.findUnique({
      where: { email: credentials.email },
    });

    if (!user || !user.hashedPassword) {
      return null;
    }

    const isValid = await bcrypt.compare(credentials.password, user.hashedPassword);

    if (!isValid) {
      return null;
    }

    return {
      id: user.id,
      email: user.email,
      name: user.name,
      role: user.role,
    };
  },
});
```

## Security Best Practices

### 1. Always Use AUTH_SECRET in Production

```bash
# Generate a secure secret
openssl rand -base64 32
```

### 2. Cookie Configuration

```typescript
export const { auth } = NextAuth({
  cookies: {
    sessionToken: {
      name: `__Secure-authjs.session-token`,
      options: {
        httpOnly: true,
        sameSite: 'lax',
        path: '/',
        secure: process.env.NODE_ENV === 'production',
      },
    },
  },
});
```

### 3. CSRF Protection

Auth.js handles CSRF protection automatically. Ensure you:
- Use POST for sign-in/sign-out
- Don't disable built-in protections

### 4. Validate Sessions Server-Side

```typescript
// Always verify on the server for sensitive operations
export async function sensitiveOperation() {
  const session = await auth();

  if (!session?.user) {
    throw new Error('Unauthorized');
  }

  // Double-check user exists in database
  const user = await prisma.user.findUnique({
    where: { id: session.user.id },
  });

  if (!user || user.banned) {
    throw new Error('Access denied');
  }

  // Proceed with operation
}
```

## Session Refresh and Polling

```typescript
'use client';

import { SessionProvider } from 'next-auth/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <SessionProvider
      refetchInterval={5 * 60} // Refetch every 5 minutes
      refetchOnWindowFocus={true}
    >
      {children}
    </SessionProvider>
  );
}
```

## Error Handling

### Custom Error Page

```typescript
// app/auth/error/page.tsx
export default function AuthErrorPage({
  searchParams,
}: {
  searchParams: { error?: string };
}) {
  const errorMessages: Record<string, string> = {
    Configuration: 'There is a problem with the server configuration.',
    AccessDenied: 'You do not have permission to sign in.',
    Verification: 'The verification link has expired or has already been used.',
    Default: 'An error occurred during authentication.',
  };

  const error = searchParams.error || 'Default';
  const message = errorMessages[error] || errorMessages.Default;

  return (
    <div>
      <h1>Authentication Error</h1>
      <p>{message}</p>
      <a href="/auth/signin">Try again</a>
    </div>
  );
}
```

## Testing

```typescript
// Mock auth for testing
import { auth } from '@/auth';

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

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

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

  it('returns data for authenticated requests', async () => {
    (auth as jest.Mock).mockResolvedValue({
      user: { id: '1', email: '[email protected]' },
    });

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

## Common Issues and Solutions

### Session Disappears on Refresh

1. Ensure `AUTH_SECRET` is set in production
2. Check cookie configuration
3. Verify HTTPS in production

### Edge Runtime Compatibility

Use split configuration if using database adapter with Edge middleware.

### Type Errors with Custom Properties

Extend the types in `types/next-auth.d.ts`.

## Common Anti-Patterns to Avoid

1. Using `NEXTAUTH_` prefix (use `AUTH_` in v5)
2. Not setting `AUTH_SECRET` in production
3. Relying on client-side session checks for authorization
4. Not handling loading states in client components
5. Using database strategy with Edge middleware
6. Not validating sessions in server actions
7. Exposing sensitive data in JWT tokens

© Mindrally · Apache-2.0 · Mindrally/skills

Похожие скиллы

Всё по теме «Фронтенд и UI» →
nextjs-authentication giuseppe-trisciuoglio Скилл даёт готовые шаблоны аутентификации для Next.js 15+ App Router на Auth.js 5: провайдеры, защита маршрутов, сессии и роли. CX Codex +1 3 800установок oauth vercel-labs Скилл настраивает OAuth-провайдеров для работы с локальными доменами portless и убирает ошибки redirect_uri_mismatch. CX Codex +1 3 000установок authjs-skills gocallum Скилл для ИИ-агентов, который помогает подключить аутентификацию Auth.js v5 в Next.js: Google OAuth, вход по email и паролю, переменные окружения. CX Codex +1 791установок adding-auth spencerpauly Скилл проводит агента по шагам добавления аутентификации в веб-приложение на NextAuth.js: провайдеры OAuth, сессии и защищённые маршруты. CX Codex +1 379установок documentation-lookup affaan-m Ищет актуальную документацию библиотек и фреймворков через сервер Context7 MCP вместо устаревшей обучающей выборки. Помогает при настройке конфигов и написании кода под свежие версии API. CX Codex +1 4 700установок better-auth-authentication bobmatnyc Скилл для TypeScript-приложений: помогает настроить вход по email и паролю, социальные провайдеры и проверку почты. CX Codex +1 389установок

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

gitlab-workflow Скилл учит ИИ-ассистента правилам GitLab: от оформления merge request до настройки конвейеров .gitlab-ci.yml. Помогает выстроить командную разработку. CX Codex +1 1 100установок ux-design Скилл задаёт агенту правила UX-проектирования: от исследования пользователей до доступности и адаптивной вёрстки. Пригодится, когда проектируешь или проверяешь интерфейс. CX Codex +1 1 100установок analytics-data-analysis Задаёт агенту правила работы с pandas, matplotlib и seaborn: как чистить датасет, строить графики и оформлять Jupyter-ноутбук. CX Codex +1 1 100установок rabbitmq-development Набор правил для ИИ-агента: как проектировать обменники, очереди и потребителей RabbitMQ без типичных ошибок. CX Codex +1 1 100установок scipy-best-practices Скилл задаёт агенту правила научных вычислений на SciPy: оптимизация, линейная алгебра, статистика, сигналы. Пригодится, когда код на Python считает числа, а не рисует интерфейсы. CX Codex +1 1 000установок kubernetes Задаёт агенту правила работы с Kubernetes, Helm, Ansible и CI/CD. Пригодится, когда манифесты и пайплайны пишет ИИ, а не человек. CX Codex +1 1 000установок quarkus Скилл задаёт агенту правила кода на Quarkus: Jakarta EE, MicroProfile, нативные сборки GraalVM и реактивные паттерны. CX Codex +1 1 000установок prisma Правила проектирования схем Prisma ORM, изоляции тестов и типобезопасных запросов. Помогает выстроить слой репозиториев в TypeScript. CX Codex +1 1 000установок

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

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