import { Request, Response, NextFunction } from 'express' import jwt from 'jsonwebtoken' import { prisma } from '../config/database' export interface AuthUser { id: string email: string username: string displayName: string avatar: string | null bio: string | null isOnline: boolean lastSeen: Date isAdmin: boolean isVerified: boolean createdAt: Date updatedAt: Date } export interface AuthRequest extends Request { user?: AuthUser } export const authMiddleware = async ( req: AuthRequest, res: Response, next: NextFunction ): Promise => { try { const authHeader = req.headers.authorization if (!authHeader || !authHeader.startsWith('Bearer ')) { res.status(401).json({ success: false, error: 'Access token required' }) return } const token = authHeader.substring(7) // Remove 'Bearer ' prefix if (!token) { res.status(401).json({ success: false, error: 'Access token required' }) return } // Verify JWT token const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: string } // Get user from database const user = await prisma.user.findUnique({ where: { id: decoded.userId }, select: { id: true, email: true, username: true, displayName: true, avatar: true, bio: true, isOnline: true, lastSeen: true, isAdmin: true, isVerified: true, createdAt: true, updatedAt: true, } }) if (!user) { res.status(401).json({ success: false, error: 'Invalid token - user not found' }) return } // Attach user to request req.user = user next() } catch (error) { if (error instanceof jwt.JsonWebTokenError) { res.status(401).json({ success: false, error: 'Invalid token' }) return } if (error instanceof jwt.TokenExpiredError) { res.status(401).json({ success: false, error: 'Token expired' }) return } console.error('Auth middleware error:', error) res.status(500).json({ success: false, error: 'Authentication failed' }) } } export const adminMiddleware = ( req: AuthRequest, res: Response, next: NextFunction ): void => { if (!req.user) { res.status(401).json({ success: false, error: 'Authentication required' }) return } if (!req.user.isAdmin) { res.status(403).json({ success: false, error: 'Admin access required' }) return } next() } export const optionalAuthMiddleware = async ( req: AuthRequest, res: Response, next: NextFunction ): Promise => { try { const authHeader = req.headers.authorization if (!authHeader || !authHeader.startsWith('Bearer ')) { next() return } const token = authHeader.substring(7) if (!token) { next() return } const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: string } const user = await prisma.user.findUnique({ where: { id: decoded.userId }, select: { id: true, email: true, username: true, displayName: true, avatar: true, bio: true, isOnline: true, lastSeen: true, isAdmin: true, isVerified: true, createdAt: true, updatedAt: true, } }) if (user) { req.user = user } next() } catch (error) { // Ignore auth errors for optional auth next() } }