--- name: nextauth description: NextAuth.js (Auth.js) configuration including providers, adapters, session management, callbacks, and JWT handling. allowed-tools: Read, Write, Edit, Bash, Glob, Grep --- # NextAuth Skill Expert assistance for implementing authentication in Next.js applications with NextAuth.js (Auth.js). ## Capabilities - Configure OAuth providers (Google, GitHub, etc.) - Set up credentials-based authentication - Implement database adapters (Prisma, Drizzle) - Handle JWT and session callbacks - Configure protected routes and middleware - Implement role-based access control ## Usage Invoke this skill when you need to: - Add authentication to Next.js app - Configure OAuth providers - Set up database sessions - Implement auth middleware - Handle user roles and permissions ## Inputs | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | providers | array | Yes | Auth providers to configure | | adapter | string | No | Database adapter (prisma, drizzle) | | sessionStrategy | string | No | jwt or database | | callbacks | array | No | Custom callbacks needed | ### Configuration Example ```json { "providers": ["google", "github", "credentials"], "adapter": "prisma", "sessionStrategy": "jwt", "callbacks": ["jwt", "session", "signIn"] } ``` ## Implementation Patterns ### Basic Configuration (App Router) ```typescript // app/api/auth/[...nextauth]/route.ts import NextAuth from 'next-auth'; import { authOptions } from '@/lib/auth'; const handler = NextAuth(authOptions); export { handler as GET, handler as POST }; // lib/auth.ts import { NextAuthOptions } from 'next-auth'; import GoogleProvider from 'next-auth/providers/google'; import GitHubProvider from 'next-auth/providers/github'; import CredentialsProvider from 'next-auth/providers/credentials'; import { PrismaAdapter } from '@auth/prisma-adapter'; import { prisma } from '@/lib/prisma'; import bcrypt from 'bcryptjs'; export const authOptions: NextAuthOptions = { adapter: PrismaAdapter(prisma), providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }), GitHubProvider({ clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, }), CredentialsProvider({ name: 'credentials', credentials: { email: { label: 'Email', type: 'email' }, password: { label: 'Password', type: 'password' }, }, async authorize(credentials) { if (!credentials?.email || !credentials?.password) { throw new Error('Invalid credentials'); } const user = await prisma.user.findUnique({ where: { email: credentials.email }, }); if (!user || !user.hashedPassword) { throw new Error('Invalid credentials'); } const isValid = await bcrypt.compare( credentials.password, user.hashedPassword ); if (!isValid) { throw new Error('Invalid credentials'); } return user; }, }), ], session: { strategy: 'jwt', }, pages: { signIn: '/login', 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 (session.user) { session.user.id = token.id as string; session.user.role = token.role as string; } return session; }, async signIn({ user, account, profile }) { // Custom sign-in logic return true; }, }, }; ``` ### 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; } } ``` ### Auth Middleware ```typescript // middleware.ts import { withAuth } from 'next-auth/middleware'; import { NextResponse } from 'next/server'; export default withAuth( function middleware(req) { const token = req.nextauth.token; const isAdmin = token?.role === 'admin'; const isAdminRoute = req.nextUrl.pathname.startsWith('/admin'); if (isAdminRoute && !isAdmin) { return NextResponse.redirect(new URL('/unauthorized', req.url)); } return NextResponse.next(); }, { callbacks: { authorized: ({ token }) => !!token, }, } ); export const config = { matcher: ['/dashboard/:path*', '/admin/:path*', '/api/protected/:path*'], }; ``` ### Server-Side Auth Check ```typescript // app/dashboard/page.tsx import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { redirect } from 'next/navigation'; export default async function DashboardPage() { const session = await getServerSession(authOptions); if (!session) { redirect('/login'); } return (
Role: {session.user.role}