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() | |
} | |
} | |