import { NextApiRequest, NextApiResponse } from 'next'; import { verifyToken } from '../auth'; import { UserService } from '../../backend/services/userService'; import { UserDTO } from '../../types'; // Extend NextApiRequest to include user property export interface AuthenticatedRequest extends NextApiRequest { user?: UserDTO; } /** * Middleware to require authentication * Returns 401 if no valid token is found */ export async function requireAuth( req: AuthenticatedRequest, res: NextApiResponse ): Promise { const token = getTokenFromRequest(req); if (!token) { res.status(401).json({ success: false, error: 'Authentication required' }); return false; } const decoded = verifyToken(token); if (!decoded) { res.status(401).json({ success: false, error: 'Invalid or expired token' }); return false; } // Load user from database const user = await UserService.getUserById(decoded.userId); if (!user) { res.status(401).json({ success: false, error: 'User not found' }); return false; } // Check if user is banned if (user.status === 'BANNED') { res.status(403).json({ success: false, error: 'Account has been banned' }); return false; } // Attach user to request req.user = user; return true; } /** * Middleware for optional authentication * Attaches user to request if valid token exists, but doesn't fail if not */ export async function optionalAuth(req: AuthenticatedRequest): Promise { const token = getTokenFromRequest(req); if (!token) { return; } const decoded = verifyToken(token); if (!decoded) { return; } const user = await UserService.getUserById(decoded.userId); if (user && user.status !== 'BANNED') { req.user = user; } } /** * Extract JWT token from request * Checks both cookies and Authorization header */ function getTokenFromRequest(req: NextApiRequest): string | null { // Check cookie first if (req.cookies.token) { return req.cookies.token; } // Check Authorization header const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { return authHeader.substring(7); } return null; }