// ABOUTME: Next.js middleware for page route protection. // ABOUTME: Redirects unauthenticated users to login for protected pages. import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; /** * Public paths that don't require authentication. */ const PUBLIC_PATHS = ["/login"]; /** * Paths to skip middleware entirely (API routes, static assets). */ const SKIP_PATHS = ["/api", "/_next", "/favicon.ico"]; /** * Checks if a request path should skip middleware. */ function shouldSkipMiddleware(pathname: string): boolean { return SKIP_PATHS.some((path) => pathname.startsWith(path)); } /** * Checks if a request path is public (doesn't require auth). */ function isPublicPath(pathname: string): boolean { return PUBLIC_PATHS.some((path) => pathname === path); } /** * Next.js middleware function for page protection. * Checks for pb_auth cookie and redirects to login if missing. */ export async function middleware(request: NextRequest): Promise { const { pathname } = request.nextUrl; // Skip middleware for API routes and static assets if (shouldSkipMiddleware(pathname)) { return NextResponse.next(); } // Allow public paths without authentication if (isPublicPath(pathname)) { return NextResponse.next(); } // Check for authentication cookie const authCookie = request.cookies.get("pb_auth"); // If no valid auth cookie, redirect to login if (!authCookie || !authCookie.value) { const loginUrl = new URL("/login", request.nextUrl.origin); return NextResponse.redirect(loginUrl); } // User has auth cookie, allow through return NextResponse.next(); } /** * Matcher configuration for Next.js middleware. * Matches all paths except static files and public assets. */ export const config = { matcher: [ /* * Match all request paths except: * - _next/static (static files) * - _next/image (image optimization files) * - favicon.ico (favicon file) * - public folder */ "/((?!_next/static|_next/image|favicon.ico|public).*)", ], };