import { NextRequest, NextResponse } from 'next/server' const publicRoutes = ['/login', '/api/auth/login', '/api/auth/verify-2fa', '/api/health'] export function middleware(request: NextRequest) { const { pathname } = request.nextUrl // Allow public routes if (publicRoutes.some(route => pathname.startsWith(route))) { return addSecurityHeaders(NextResponse.next()) } // Allow static assets if ( pathname.startsWith('/_next') || pathname.startsWith('/favicon') || pathname.includes('.') ) { return NextResponse.next() } // Check for session token const sessionToken = request.cookies.get('session-token')?.value if (!sessionToken) { // API routes return 401 if (pathname.startsWith('/api/')) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } // Pages redirect to login const loginUrl = new URL('/login', request.url) loginUrl.searchParams.set('redirect', pathname) return NextResponse.redirect(loginUrl) } // CORS enforcement in production if (process.env.NODE_ENV === 'production' && pathname.startsWith('/api/')) { const origin = request.headers.get('origin') const allowedOrigins = [ process.env.NEXT_PUBLIC_APP_URL, ].filter(Boolean) if (origin && !allowedOrigins.includes(origin)) { return NextResponse.json({ error: 'CORS: Origin not allowed' }, { status: 403 }) } } return addSecurityHeaders(NextResponse.next()) } function addSecurityHeaders(response: NextResponse): NextResponse { response.headers.set('X-Frame-Options', 'DENY') response.headers.set('X-Content-Type-Options', 'nosniff') response.headers.set('X-XSS-Protection', '1; mode=block') response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin') response.headers.set( 'Permissions-Policy', 'geolocation=(), microphone=(), camera=()' ) return response } export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'], }