72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
// backend/middleware/auth.ts
|
|
|
|
import logger from '../utils/logger';
|
|
import { Request, Response, NextFunction } from 'express';
|
|
import jwt, { JwtPayload } from 'jsonwebtoken';
|
|
import { Pool } from 'mysql2/promise';
|
|
|
|
// Extend Request to include a user property
|
|
declare module 'express-serve-static-core' {
|
|
interface Request {
|
|
user?: { id: number; username: string; role: string } | null;
|
|
}
|
|
}
|
|
|
|
export const authMiddleware = (pool: Pool) => async (req: Request, res: Response, next: NextFunction) => {
|
|
try {
|
|
logger.info("Auth middleware triggered");
|
|
|
|
const authHeader = req.headers.authorization;
|
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
logger.warn("Authorization header missing or invalid:", { authHeader });
|
|
return res.status(401).json({ message: 'Authorization header missing or invalid' });
|
|
}
|
|
|
|
const token = authHeader.split(' ')[1];
|
|
const jwtSecret = process.env.JWT_SECRET;
|
|
if (!jwtSecret) {
|
|
throw new Error("JWT_SECRET is not set in environment variables");
|
|
}
|
|
|
|
let decoded: JwtPayload;
|
|
try {
|
|
decoded = jwt.verify(token, jwtSecret) as JwtPayload;
|
|
} catch (error: unknown) {
|
|
logger.error("JWT verification failed:", error);
|
|
if (error instanceof jwt.TokenExpiredError) {
|
|
return res.status(401).json({
|
|
message: 'Access token expired',
|
|
code: 'TOKEN_EXPIRED',
|
|
});
|
|
}
|
|
return res.status(401).json({ message: 'Invalid token', code: 'INVALID_TOKEN' });
|
|
}
|
|
|
|
const userId = decoded.userId;
|
|
if (!userId || typeof userId !== 'number') {
|
|
logger.warn("Invalid or missing userId in token payload:", { decoded });
|
|
return res.status(401).json({ message: 'Invalid token payload' });
|
|
}
|
|
|
|
try {
|
|
const [rows] = await pool.execute(
|
|
'SELECT id, username, role FROM users WHERE id = ? AND status = "active"',
|
|
[userId]
|
|
);
|
|
const users = Array.isArray(rows) ? rows : [];
|
|
if (users.length === 0) {
|
|
logger.warn("User not found or inactive:", { userId });
|
|
return res.status(401).json({ message: 'User not found or inactive' });
|
|
}
|
|
req.user = users[0] as { id: number; username: string; role: string };
|
|
next();
|
|
} catch (dbError) {
|
|
logger.error("Database query failed:", dbError);
|
|
return res.status(500).json({ message: 'Database query error' });
|
|
}
|
|
} catch (error: unknown) {
|
|
logger.error('Error in authMiddleware:', error);
|
|
res.status(500).json({ message: 'Internal server error' });
|
|
}
|
|
};
|