Babysitter nextauth
NextAuth.js (Auth.js) configuration including providers, adapters, session management, callbacks, and JWT handling.
install
source · Clone the upstream repo
git clone https://github.com/a5c-ai/babysitter
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/a5c-ai/babysitter "$T" && mkdir -p ~/.claude/skills && cp -r "$T/library/specializations/web-development/skills/nextauth" ~/.claude/skills/a5c-ai-babysitter-nextauth && rm -rf "$T"
manifest:
library/specializations/web-development/skills/nextauth/SKILL.mdsource content
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
{ "providers": ["google", "github", "credentials"], "adapter": "prisma", "sessionStrategy": "jwt", "callbacks": ["jwt", "session", "signIn"] }
Implementation Patterns
Basic Configuration (App Router)
// 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
// 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
// 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
// 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> ); }
Client-Side Auth Hook
// 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> ); }
Session Provider
// 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> ); }
Prisma Schema
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) }
Best Practices
- Use JWT strategy for serverless deployments
- Extend session with necessary user data
- Implement proper CSRF protection
- Use middleware for route protection
- Store secrets in environment variables
Target Processes
- nextjs-full-stack
- oauth-social-login
- jwt-authentication
- rbac-implementation