import { NextRequest, NextResponse } from 'next/server'; import { cookies } from 'next/headers'; import { jwtVerify } from 'jose'; const SESSION_COOKIE_NAME = 'auth_session'; /** * Proxy to protect routes with authentication * Reusable for other projects - just copy this file */ export async function proxy(request: NextRequest) { const { pathname } = request.nextUrl; // Check if authentication is enabled const authEnabled = !!process.env.AUTH_USERS; // If auth is not enabled, allow all requests if (!authEnabled) { return NextResponse.next(); } // Public paths that don't require authentication const publicPaths = ['/login']; const isPublicPath = publicPaths.some(path => pathname.startsWith(path)); if (isPublicPath) { return NextResponse.next(); } // Check for session cookie const cookieStore = await cookies(); const sessionCookie = cookieStore.get(SESSION_COOKIE_NAME); if (!sessionCookie) { return NextResponse.redirect(new URL('/login', request.url)); } // Verify session token try { const secretKey = process.env.AUTH_SECRET || 'default-secret-change-in-production'; const key = new TextEncoder().encode(secretKey); const { payload } = await jwtVerify(sessionCookie.value, key, { algorithms: ['HS256'], }); // Check if session is expired if (payload.expiresAt && (payload.expiresAt as number) < Date.now()) { const response = NextResponse.redirect(new URL('/login', request.url)); response.cookies.delete(SESSION_COOKIE_NAME); return response; } return NextResponse.next(); } catch (error) { // Invalid token - redirect to login const response = NextResponse.redirect(new URL('/login', request.url)); response.cookies.delete(SESSION_COOKIE_NAME); return response; } } export const config = { matcher: [ /* * Match all request paths except for the ones starting with: * - _next/static (static files) * - _next/image (image optimization files) * - favicon.ico (favicon file) * - public folder */ '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)', ], };