diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..33acd19 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,47 @@ +import NextAuth from "next-auth"; +import { NextResponse } from "next/server"; +import authConfig from "@/auth.config"; + +// Route-gating for page requests: "everything requires login by default, +// explicit allowlist for what doesn't" (safer than an opt-in allowlist that +// new routes can forget to add themselves to). +// +// This project pins Next.js 14.2.35, which predates Next.js 16's +// middleware.ts -> proxy.ts rename (see https://nextjs.org/docs/messages/middleware-to-proxy) +// so this stays middleware.ts with a default-exported `middleware` function, +// not proxy.ts. Auth.js v5's docs (https://authjs.dev/getting-started/session-management/protecting) +// confirm: older Next.js versions re-export `auth` as `middleware`; only +// Next.js 16+ uses `proxy`. +// +// Deliberately builds its own NextAuth instance from src/auth.config.ts +// (no Credentials provider) instead of importing `auth` from src/auth.ts — +// this file runs on the Edge Runtime, and src/auth.ts's Credentials +// provider pulls in bcryptjs (Node-only); see auth.config.ts's comment. +// This instance only needs to decode/validate the JWT session cookie, which +// is Edge-safe. +// +// config.matcher below excludes /api entirely, so this middleware never +// runs on API routes (including /api/auth/* itself, needed for the login +// flow) — API route authorization is handled separately, directly in each +// route handler (see src/app/api/requests/route.ts), per Auth.js's own +// guidance to verify the session as close to the data fetching as possible +// rather than relying on middleware alone. That also means /login doesn't +// need special-casing in the matcher, only in the redirect check below (to +// avoid an infinite redirect loop), and Next.js's internal asset paths +// (_next/static, _next/image, favicon.ico) never reach this middleware. +const { auth } = NextAuth(authConfig); + +export default auth((req) => { + const isLoginPage = req.nextUrl.pathname === "/login"; + + if (!req.auth && !isLoginPage) { + const loginUrl = new URL("/login", req.nextUrl.origin); + return NextResponse.redirect(loginUrl); + } + + return NextResponse.next(); +}); + +export const config = { + matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], +};