NextAuth.js (Auth.js) configuration including providers, adapters, session management, callbacks, and JWT handling.
Configures NextAuth.js authentication with providers, adapters, session strategies, and callbacks for Next.js applications.
npx claudepluginhub a5c-ai/babysitterThis skill is limited to using the following tools:
README.mdExpert assistance for implementing authentication in Next.js applications with NextAuth.js (Auth.js).
Invoke this skill when you need to:
| 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 |
{
"providers": ["google", "github", "credentials"],
"adapter": "prisma",
"sessionStrategy": "jwt",
"callbacks": ["jwt", "session", "signIn"]
}
// 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;
},
},
};
// 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;
}
}
// 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*'],
};
// 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 (
<div>
<h1>Welcome, {session.user.name}</h1>
<p>Role: {session.user.role}</p>
</div>
);
}
// components/user-menu.tsx
'use client';
import { useSession, signIn, signOut } from 'next-auth/react';
export function UserMenu() {
const { data: session, status } = useSession();
if (status === 'loading') {
return <div>Loading...</div>;
}
if (!session) {
return (
<button onClick={() => signIn()}>
Sign In
</button>
);
}
return (
<div>
<img src={session.user.image} alt={session.user.name} />
<span>{session.user.name}</span>
<button onClick={() => signOut()}>
Sign Out
</button>
</div>
);
}
// 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>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
hashedPassword String?
role String @default("user")
accounts Account[]
sessions Session[]
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.