tinfo-web-server / middleware /authMiddleware.js
Faridaqurr
initial backend
e8c33fa
Raw
History Blame Contribute Delete
2.82 kB
const jwt = require('jsonwebtoken');
const AdminUser = require('../models/AdminUser');
const { env } = require('../configs/env');
const JWT_SECRET = env.jwtSecret;
const readTokenFromRequest = (req) => {
const header = req.headers?.authorization || req.headers?.Authorization;
if (typeof header === 'string') {
const [scheme, value] = header.split(' ');
if (scheme && scheme.toLowerCase() === 'bearer' && value) {
return value.trim();
}
}
return req.cookies?.token || '';
};
const protect = async (req, res, next) => {
if (!JWT_SECRET) {
return res.status(503).json({ message: "Authentication is not configured" });
}
const token = readTokenFromRequest(req);
if (!token) {
return res.status(401).json({ message: "Not authorized, no token" });
}
try {
const decoded = jwt.verify(token, JWT_SECRET);
const adminId = decoded?.id || decoded?.sub;
if (!adminId) {
return res.status(401).json({ message: "Not authorized, invalid token" });
}
const admin = await AdminUser.findById(adminId).select('-passwordHash +sessionToken').lean();
if (!admin) {
return res.status(401).json({ message: "User not found" });
}
if (admin.isActive === false) {
return res.status(403).json({ message: "Account is inactive" });
}
if (decoded.st && admin.sessionToken && decoded.st !== admin.sessionToken) {
return res.status(401).json({ message: "Session invalidated", code: "SESSION_CONFLICT" });
}
req.user = {
...admin,
_id: admin._id,
id: String(admin._id),
role: admin.role || "admin",
};
// Belt-and-suspenders: projection already excludes this field; explicit scrub guards against future query changes.
delete req.user.passwordHash;
return next();
} catch (error) {
return res.status(401).json({ message: "Not authorized, invalid token" });
}
};
const adminOnly = (req, res, next) => {
if (req.user && req.user.role === "admin") {
next();
} else {
res.status(403).json({ message: "Access denied: Admins only" });
}
};
const optionalProtect = async (req, res, next) => {
if (!JWT_SECRET) return next();
const token = readTokenFromRequest(req);
if (!token) return next();
try {
const decoded = jwt.verify(token, JWT_SECRET);
const adminId = decoded?.id || decoded?.sub;
if (adminId) {
const admin = await AdminUser.findById(adminId).select('-passwordHash').lean();
if (admin && admin.isActive !== false) {
req.user = {
...admin,
_id: admin._id,
id: String(admin._id),
role: admin.role || 'admin',
};
}
}
} catch {
// Invalid token — proceed as unauthenticated
}
next();
};
module.exports = { protect, adminOnly, optionalProtect };