Skip to main content

nextjs-authentication

Provides authentication implementation patterns for Next.js 15+ App Router using Auth.js 5 (NextAuth.js). Use when setting up authentication flows, implementing protected routes, managing sessions in Server Components and Server Actions, configuring OAuth providers, implementing role-based access control, or handling sign-in/sign-out flows in Next.js applications.

소스 정보

저장소
giuseppe-trisciuoglio/developer-kit
최근 소스 활동
2026년 3월 24일 08:41
감지된 SKILL.md 언어
영어
스타
355
포크
41

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
7 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
nextjs-authentication
description
Provides authentication implementation patterns for Next.js 15+ App Router using Auth.js 5 (NextAuth.js). Use when setting up authentication flows, implementing protected routes, managing sessions in Server Components and Server Actions, configuring OAuth providers, implementing role-based access control, or handling sign-in/sign-out flows in Next.js applications.
allowed-tools
Read, Write, Edit, Bash
# Next.js Authentication ## Overview Provides authentication implementation patterns for Next.js 15+ App Router using Auth.js 5 (NextAuth.js), covering the complete authentication lifecycle from initial setup to production-ready role-based access control implementations. ## When to Use - Setting up Auth.js 5 from scratch or adding OAuth providers - Implementing protected routes with Middleware - Handling authentication in Server Components and Server Actions - Implementing role-based access control (RBAC) - Creating credential-based or OAuth sign-in/sign-out flows ## Instructions ### 1. Install Dependencies Install Auth.js v5 (beta) for Next.js App Router: ```bash npm install next-auth@beta ``` ### 2. Configure Environment Variables Create `.env.local` with required variables: ```bash # Required for Auth.js AUTH_SECRET="your-secret-key-here" AUTH_URL="http://localhost:3000" # OAuth Providers (add as needed) GITHUB_ID="your-github-client-id" GITHUB_SECRET="your-github-client-secret" GOOGLE_CLIENT_ID="your-google-client-id" GOOGLE_CLIENT_SECRET="your-google-client-secret" ``` Generate `AUTH_SECRET` with: ```bash openssl rand -base64 32 ``` ### 3. Create Auth Configuration Create `auth.ts` in the project root with providers and callbacks: ```typescript import NextAuth from "next-auth"; import GitHub from "next-auth/providers/github"; import Google from "next-auth/providers/google"; export const { handlers: { GET, POST }, auth, signIn, signOut, } = NextAuth({ providers: [ GitHub({ clientId: process.env.GITHUB_ID!, clientSecret: process.env.GITHUB_SECRET!, }), Google({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }), ], callbacks: { async jwt({ token, user }) { if (user) { token.id = user.id; } return token; }, async session({ session, token }) { if (token) { session.user.id = token.id as string; } return session; }, }, pages: { signIn: "/login", error: "/error", }, }); ``` ### 4. Create API Route Handler Create `app/api/auth/[...nextauth]/route.ts`: ```typescript export { GET, POST } from "@/auth"; ``` ### 5. Add Middleware for Route Protection Create `middleware.ts` in the project root: ```typescript import { auth } from "@/auth"; import { NextResponse } from "next/server"; export default auth((req) => { const { nextUrl } = req; const isLoggedIn = !!req.auth; const isApiAuthRoute = nextUrl.pathname.startsWith("/api/auth"); const isPublicRoute = ["/", "/login", "/register"].includes(nextUrl.pathname); const isProtectedRoute = nextUrl.pathname.startsWith("/dashboard"); if (isApiAuthRoute) return NextResponse.next(); if (!isLoggedIn && isProtectedRoute) { return NextResponse.redirect(new URL("/login", nextUrl)); } if (isLoggedIn && nextUrl.pathname === "/login") { return NextResponse.redirect(new URL("/dashboard", nextUrl)); } return NextResponse.next(); }); export const config = { matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\.png$).*)"], }; ``` ### 6. Access Session in Server Components Use the `auth()` function to access session in Server Components: ```tsx import { auth } from "@/auth"; import { redirect } from "next/navigation"; export default async function DashboardPage() { const session = await auth(); if (!session) { redirect("/login"); } return ( <div> <h1>Welcome, {session.user.name}</h1> </div> ); } ``` ### 7. Secure Server Actions Always verify authentication in Server Actions before mutations: ```tsx "use server"; import { auth } from "@/auth"; export async function createTodo(formData: FormData) { const session = await auth(); if (!session?.user) { throw new Error("Unauthorized"); } // Proceed with protected action const title = formData.get("title") as string; await db.todo.create({ data: { title, userId: session.user.id }, }); } ``` ### 8. Handle Sign-In/Sign-Out Create a login page with server action: ```tsx // app/login/page.tsx import { signIn } from "@/auth"; import { redirect } from "next/navigation"; export default function LoginPage() { async function handleLogin(formData: FormData) { "use server"; const result = await signIn("credentials", { email: formData.get("email"), password: formData.get("password"), redirect: false, }); if (result?.error) { return { error: "Invalid credentials" }; } redirect("/dashboard"); } return ( <form action={handleLogin}> <input name="email" type="email" placeholder="Email" required /> <input name="password" type="password" placeholder="Password" required /> <button type="submit">Sign In</button> </form> ); } ``` For client-side sign-out: ```tsx "use client"; import { signOut } from "next-auth/react"; export function SignOutButton() { return <button onClick={() => signOut()}>Sign Out</button>; } ``` ### 9. Implement Role-Based Access Check roles in Server Components: ```tsx import { auth } from "@/auth"; import { unauthorized } from "next/navigation"; export default async function AdminPage() { const session = await auth(); if (session?.user?.role !== "admin") { unauthorized(); } return <AdminDashboard />; } ``` ### 10. Extend TypeScript Types Create `types/next-auth.d.ts` for type-safe sessions: ```typescript import { DefaultSession } from "next-auth"; declare module "next-auth" { interface Session { user: { id: string; role: "user" | "admin"; } & DefaultSession["user"]; } interface User { role?: "user" | "admin"; } } declare module "next-auth/jwt" { interface JWT { id?: string; role?: "user" | "admin"; } } ``` ## Examples ### Example 1: Complete Protected Dashboard **Input:** User needs a dashboard accessible only to authenticated users **Implementation:** ```tsx // app/dashboard/page.tsx import { auth } from "@/auth"; import { redirect } from "next/navigation"; import { getUserTodos } from "@/app/lib/data"; export default async function DashboardPage() { const session = await auth(); if (!session?.user?.id) { redirect("/login"); } const todos = await getUserTodos(session.user.id); return ( <main> <h1>Welcome, {session.user.name}</h1> <p>Email: {session.user.email}</p> <TodoList todos={todos} /> </main> ); } ``` **Output:** Dashboard renders only for authenticated users, with their specific data. ### Example 2: Role-Based Admin Panel **Input:** Admin panel should be accessible only to users with "admin" role **Implementation:** ```tsx // app/admin/page.tsx import { auth } from "@/auth"; import { unauthorized } from "next/navigation"; export default async function AdminPage() { const session = await auth(); if (session?.user?.role !== "admin") { unauthorized(); } return ( <main> <h1>Admin Panel</h1> <p>Welcome, administrator {session.user.name}</p> </main> ); } ``` **Output:** Only admin users see the panel; others get 401 error. ### Example 3: Secure Server Action with Form **Input:** Form submission should only work for authenticated users **Implementation:** ```tsx // app/components/create-todo-form.tsx "use server"; import { auth } from "@/auth"; import { revalidatePath } from "next/cache"; export async function createTodo(formData: FormData) { const session = await auth(); if (!session?.user?.id) { throw new Error("Unauthorized"); } const title = formData.get("title") as string; await db.todo.create({ data: { title, userId: session.user.id, }, }); revalidatePath("/dashboard"); } // Usage in component export function CreateTodoForm() { return ( <form action={createTodo}> <input name="title" placeholder="New todo..." required /> <button type="submit">Add Todo</button> </form> ); } ``` **Output:** Todo created only for authenticated user; unauthorized requests throw error. ## Best Practices 1. **Use Server Components by default** - Access session directly without client-side JavaScript 2. **Minimize Client Components** - Only use `useSession()` for reactive session updates 3. **Cache session checks** - Use React's `cache()` for repeated lookups in the same render 4. **Middleware for optimistic checks** - Redirect quickly, but always re-verify in Server Actions 5. **Treat Server Actions like API endpoints** - Always authenticate before mutations 6. **Never hardcode secrets** - Use environment variables for all credentials 7. **Implement proper error handling** - Return appropriate HTTP status codes 8. **Use TypeScript type extensions** - Extend NextAuth types for custom fields 9. **Separate auth logic** - Create a DAL (Data Access Layer) for consistent checks 10. **Test authentication flows** - Mock `auth()` function in unit tests ## Constraints and Warnings ### Critical Limitations - **Middleware runs on Edge runtime** - Cannot use Node.js APIs like database drivers - **Server Components cannot set cookies** - Use Server Actions for cookie operations - **Session callback timing** - Only called on session creation/access, not every request ### Common Mistakes ```tsx // ❌ WRONG: Setting cookies in Server Component export default async function Page() { cookies().set("key", "value"); // Won't work } // ✅ CORRECT: Use Server Action async function setCookieAction() { "use server"; cookies().set("key", "value"); } ``` ```typescript // ❌ WRONG: Database queries in Middleware export default auth(async (req) => { const user = await db.user.findUnique(); // Won't work in Edge }); // ✅ CORRECT: Use only Edge-compatible APIs export default auth(async (req) => { const session = req.auth; // This works }); ``` ### Security Considerations - Always verify authentication in Server Actions - middleware alone is not enough - Use `unauthorized()` for unauthenticated access, `redirect()` for other cases - Store sensitive tokens in `httpOnly` cookies - Validate all user input before processing - Use HTTPS in production - Set appropriate cookie `sameSite` attributes ## References - [references/authjs-setup.md](references/authjs-setup.md) - Complete Auth.js 5 setup guide with Prisma/Drizzle adapters - [references/oauth-providers.md](references/oauth-providers.md) - Provider-specific configurations (GitHub, Google, Discord, Auth0, etc.) - [references/database-adapter.md](references/database-adapter.md) - Database session management with Prisma, Drizzle, and custom adapters - [references/testing-patterns.md](references/testing-patterns.md) - Testing authentication flows with Vitest and Playwright
GitHub에서 보기