Auth.js / NextAuth v5 conventions
Central config
- v5 centralizes setup in one
auth.tsat the project root:export const { handlers, auth, signIn, signOut } = NextAuth({ providers: [...] }). - The App Router route handler just re-exports it:
app/api/auth/[...nextauth]/route.ts→export const { GET, POST } = handlers. - Import providers from
next-auth/providers/*. The npm package isnext-auth; the project's brand is Auth.js.
One way to read the session
- Use the universal
auth()everywhere on the server — Server Components, route handlers, server actions, and middleware. It replacesgetServerSession,getSession,getToken, andwithAuth. useSession()is for client components only, and requires a<SessionProvider>ancestor.
Secrets & providers
- Read secrets from the environment:
AUTH_SECRETis required. Provider credentials are auto-inferred from env (AUTH_GITHUB_ID/AUTH_GITHUB_SECRET, etc.) — don't hardcode them.
Sessions & adapters
- For database sessions, use an official adapter from
@auth/*-adapter(e.g.@auth/drizzle-adapter,@auth/prisma-adapter). Without an adapter, the default JWT session strategy applies. - Customize tokens/sessions only through the
jwtandsessioncallbacks. Keep them pure and minimal — no heavy I/O on every request.
Middleware
- Protect routes by wrapping
middleware.tswithauth. - Middleware runs on the edge. If your adapter or callbacks aren't edge-safe, split the config: put the edge-safe parts in
auth.config.tsand import them into bothauth.tsandmiddleware.ts.
Anti-patterns
- ❌ Re-introducing
getServerSession/getToken/withAuthinstead ofauth(). - ❌
useSession()in server components, or without<SessionProvider>. - ❌ Hardcoded
AUTH_SECRET/ provider credentials. - ❌ Heavy logic or side effects inside the
jwt/sessioncallbacks. - ❌ Importing a non-edge adapter into edge middleware (split with
auth.config.ts).