dist/plugins/api-auth-nextauth/skills/api-auth-nextauth/SKILL.md
Auth.js (NextAuth v5) authentication patterns - configuration, providers, session strategies, middleware, database adapters, role-based access, Edge compatibility
npx skillsauth add agents-inc/skills api-auth-nextauthInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Quick Guide: Configure Auth.js in a root
auth.tsfile exporting{ auth, handlers, signIn, signOut }fromNextAuth(). Use the unifiedauth()function everywhere (Server Components, Route Handlers, middleware). Default session strategy is JWT (cookie-based); add a database adapter for persistent sessions. Protect routes via middleware or per-pageauth()checks.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST configure Auth.js in a root auth.ts file and export { auth, handlers, signIn, signOut } from NextAuth())
(You MUST use the unified auth() function for server-side session access - NOT the deprecated getServerSession(), getSession(), or getToken())
(You MUST use AUTH_SECRET environment variable - NEXTAUTH_SECRET is deprecated in v5)
(You MUST use AUTH_ prefixed environment variables for provider credentials (e.g., AUTH_GITHUB_ID, AUTH_GITHUB_SECRET) - they are auto-detected)
(You MUST split auth config into auth.config.ts (Edge-compatible) and auth.ts (with adapter) when using database sessions with middleware)
(You MUST check session inside Server Actions and API routes - middleware alone is NOT sufficient for authorization)
</critical_requirements>
Auto-detection: Auth.js, NextAuth, next-auth, authjs, auth.ts, auth.config.ts, NextAuth(), signIn, signOut, auth(), handlers, SessionProvider, useSession, AUTH_SECRET, OAuth provider, credentials provider, database adapter, @auth/prisma-adapter, @auth/drizzle-adapter, authorized callback, jwt callback, session callback, proxy auth, middleware auth
When to use:
When NOT to use:
Key patterns covered:
auth.ts, auth.config.ts)Detailed Resources:
Core patterns:
Auth.js (v5) consolidates authentication into a single, unified API. The auth() function replaces getServerSession, getSession, withAuth, and getToken from v4 for server-side use. useSession() remains the correct client-side API. Configuration lives in a root file, not in API routes.
Core principles:
auth() function for all server-side contextsAUTH_* env varsThe central configuration file exports everything you need from NextAuth().
// auth.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
export const { auth, handlers, signIn, signOut } = NextAuth({
providers: [
GitHub, // Auto-detects AUTH_GITHUB_ID and AUTH_GITHUB_SECRET
Google, // Auto-detects AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET
],
});
// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;
Why good: Single config file exports all auth utilities, providers auto-detect AUTH_* env vars, API route is minimal
# .env.local
AUTH_SECRET="generate-with-npx-auth-secret" # Required
AUTH_GITHUB_ID="your-github-client-id" # Auto-detected by GitHub provider
AUTH_GITHUB_SECRET="your-github-secret" # Auto-detected by GitHub provider
AUTH_GOOGLE_ID="your-google-id" # Auto-detected by Google provider
AUTH_GOOGLE_SECRET="your-google-secret"
Why good: AUTH_ prefix is standardized in v5, AUTH_SECRET replaces deprecated NEXTAUTH_SECRET, providers auto-detect credentials
Auth.js supports OAuth, email/magic link, and credentials authentication. 80+ built-in OAuth providers auto-detect AUTH_* env vars.
// OAuth: customize profile mapping
GitHub({
profile(profile) {
return {
id: String(profile.id),
name: profile.name ?? profile.login,
role: "user",
};
},
});
// Credentials: validate input, return null on failure
Credentials({
async authorize(credentials) {
const parsed = LoginSchema.safeParse(credentials);
if (!parsed.success) return null;
const user = await getUserByEmail(parsed.data.email);
if (
!user ||
!(await verifyPassword(parsed.data.password, user.hashedPassword))
)
return null;
return { id: user.id, name: user.name, email: user.email };
},
});
Key rules: Validate input before DB lookup, always hash passwords, return null on failure (never throw - it leaks info). See examples/core.md for complete implementations.
Four callbacks customize auth behavior. Data flows: jwt callback (enrich token) -> session callback (expose to client).
callbacks: {
jwt({ token, user }) {
if (user) { token.id = user.id; token.role = user.role ?? "user"; }
return token;
},
session({ session, token }) {
session.user.id = token.id as string;
session.user.role = token.role as string;
return session;
},
}
Key rules: JWT callback runs on EVERY auth() call (keep lightweight), user param is only present at sign-in, never expose OAuth tokens to client. See examples/core.md for complete callback implementations including signIn and redirect.
The unified auth() function replaces getServerSession, getSession, and getToken from v4 for server-side use. useSession() remains for Client Components.
| Context | How to access session |
| ---------------- | --------------------------------------------------------- |
| Server Component | const session = await auth() |
| Route Handler | export const GET = auth(function GET(req) { req.auth }) |
| Server Action | const session = await auth() |
| Middleware/Proxy | export { auth as middleware } or authorized callback |
| Client Component | useSession() (requires SessionProvider in layout) |
Key rules: Server-side imports come from @/auth, client-side imports from next-auth/react. Never call auth() in Client Components. See examples/session.md for complete implementations.
Two approaches: Server Actions (recommended, progressive enhancement) or client-side.
// Server-side (recommended): import from @/auth, use Server Actions in forms
import { signIn, signOut } from "@/auth";
// In form action: await signIn("github", { redirectTo: "/dashboard" })
// In form action: await signOut({ redirectTo: "/" })
// Client-side: import from next-auth/react, use onClick handlers
import { signIn, signOut } from "next-auth/react";
// onClick: signIn("github", { callbackUrl: "/dashboard" })
Key rules: Server-side uses redirectTo, client-side uses callbackUrl. signIn() throws a NEXT_REDIRECT exception internally -- don't wrap in try/catch expecting a return value. See examples/core.md for complete implementations.
Extend session and JWT types via declaration merging in types/next-auth.d.ts. Declare custom fields (e.g., id, role) on Session, User, and JWT interfaces using & DefaultSession["user"] to preserve defaults. See examples/core.md for the complete type declaration example.
Auth.js is the authentication layer. It handles identity verification, session management, and route protection. It does NOT handle authorization logic (role checks, permission systems) -- that is application code.
Framework support: Auth.js works with multiple web frameworks via framework-specific packages (next-auth, @auth/sveltekit, @auth/express).
Database adapters: For database sessions, Auth.js provides adapter packages (@auth/prisma-adapter, @auth/drizzle-adapter, etc.) that integrate with your ORM. See examples/database.md.
Session strategy depends on your needs:
Auth.js does NOT handle: fine-grained authorization/RBAC, rate limiting, or database queries beyond auth -- those are application-level concerns.
</integration><red_flags>
getServerSession(authOptions) -- deprecated in v5; use auth() from your auth.tsNEXTAUTH_SECRET or NEXTAUTH_URL -- deprecated; use AUTH_SECRET (URL is auto-detected)accessToken/refreshToken server-side onlyauth.config.ts + auth.tssignIn() in try/catch -- it throws a NEXT_REDIRECT exception internally (this is intentional)auth() invocation; keep it lightweightSee reference.md for the complete anti-pattern list, gotchas, and migration table.
</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md
(You MUST configure Auth.js in a root auth.ts file and export { auth, handlers, signIn, signOut } from NextAuth())
(You MUST use the unified auth() function for server-side session access - NOT the deprecated getServerSession(), getSession(), or getToken())
(You MUST use AUTH_SECRET environment variable - NEXTAUTH_SECRET is deprecated in v5)
(You MUST use AUTH_ prefixed environment variables for provider credentials (e.g., AUTH_GITHUB_ID, AUTH_GITHUB_SECRET) - they are auto-detected)
(You MUST split auth config into auth.config.ts (Edge-compatible) and auth.ts (with adapter) when using database sessions with middleware)
(You MUST check session inside Server Actions and API routes - middleware alone is NOT sufficient for authorization)
Failure to follow these rules will cause authentication failures, expose deprecated patterns, or create security vulnerabilities.
</critical_reminders>
development
Material Design component library for Vue 3
development
VitePress 1.x — Vue-powered static site generator for documentation sites, built on Vite
tools
Docusaurus 3.x documentation framework — site configuration, docs/blog plugins, sidebars, versioning, MDX, swizzling, and deployment
development
TanStack Form patterns - useForm, form.Field, validators, arrays, linked fields, createFormHook, type safety