import { NextRequest, NextResponse } from 'next/server'; import { verifyToken } from './jwt'; import { Role } from '@/types'; import { hasPermission, hasAnyPermission, Permission, isAdmin, isSuperAdmin } from './roles'; export interface AuthenticatedUser { userId: string; email: string; role: Role; } export interface AuthenticatedRequest extends NextRequest { user: AuthenticatedUser; } export type AuthMiddlewareOptions = { requiredPermissions?: Permission[]; anyPermission?: Permission[]; requireAdmin?: boolean; requireSuperAdmin?: boolean; roles?: Role[]; }; export function withAuth( handler: (req: AuthenticatedRequest) => Promise, options?: AuthMiddlewareOptions ) { return async (req: NextRequest): Promise => { const authHeader = req.headers.get('authorization'); const token = authHeader?.replace('Bearer ', ''); if (!token) { return NextResponse.json( { error: 'Unauthorized', message: 'Authentication required' }, { status: 401 } ); } try { const payload = verifyToken(token); const userRole = payload.role as Role; // Check super admin requirement if (options?.requireSuperAdmin && !isSuperAdmin(userRole)) { return NextResponse.json( { error: 'Forbidden', message: 'Super admin access required' }, { status: 403 } ); } // Check admin requirement if (options?.requireAdmin && !isAdmin(userRole)) { return NextResponse.json( { error: 'Forbidden', message: 'Admin access required' }, { status: 403 } ); } // Check role if required (legacy support) if (options?.roles && !options.roles.includes(userRole)) { return NextResponse.json( { error: 'Forbidden', message: 'Insufficient permissions' }, { status: 403 } ); } // Check required permissions (all must match) if (options?.requiredPermissions?.length) { const hasAll = options.requiredPermissions.every(p => hasPermission(userRole, p) ); if (!hasAll) { return NextResponse.json( { error: 'Forbidden', message: 'Insufficient permissions' }, { status: 403 } ); } } // Check any permission (at least one must match) if (options?.anyPermission?.length) { if (!hasAnyPermission(userRole, options.anyPermission)) { return NextResponse.json( { error: 'Forbidden', message: 'Insufficient permissions' }, { status: 403 } ); } } // Add user to request (req as AuthenticatedRequest).user = { userId: payload.userId, email: payload.email, role: userRole, }; return handler(req as AuthenticatedRequest); } catch (error) { return NextResponse.json( { error: 'Unauthorized', message: 'Invalid token' }, { status: 401 } ); } }; } // Helper to create protected API routes export function createProtectedRoute( options: AuthMiddlewareOptions, handler: (req: AuthenticatedRequest) => Promise ) { return withAuth(handler, options); } // Helper for checking specific roles export function requireRole(...roles: Role[]) { return { roles }; } // Convenience wrappers export function withAdminAuth(handler: (req: AuthenticatedRequest) => Promise) { return withAuth(handler, { requireAdmin: true }); } export function withSuperAdminAuth(handler: (req: AuthenticatedRequest) => Promise) { return withAuth(handler, { requireSuperAdmin: true }); } // Permission-based wrappers export function withPermissions( permissions: Permission[], handler: (req: AuthenticatedRequest) => Promise ) { return withAuth(handler, { requiredPermissions: permissions }); } export function withAnyPermission( permissions: Permission[], handler: (req: AuthenticatedRequest) => Promise ) { return withAuth(handler, { anyPermission: permissions }); }