Spaces:
Configuration error
Configuration error
| 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<void> => { | |
| 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<void> => { | |
| 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() | |
| } | |
| } | |