File size: 1,542 Bytes
6e13570
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const { verifyAccessToken } = require("../utils/jwt");
const User = require("../models/User");

/**

 * Requires a valid, non-expired access token in the Authorization header.

 * Attaches the full (fresh) user document to req.user so downstream

 * handlers always see current role/lock/tokenVersion state rather than

 * trusting stale claims baked into the JWT.

 */
async function requireAuth(req, res, next) {
  try {
    const header = req.headers.authorization || "";
    const [scheme, token] = header.split(" ");
    if (scheme !== "Bearer" || !token) {
      return res.status(401).json({ error: "Authentication required." });
    }

    const payload = verifyAccessToken(token);
    const user = await User.findById(payload.sub);

    if (!user || !user.isActive) {
      return res.status(401).json({ error: "Account not found or disabled." });
    }
    if (user.tokenVersion !== payload.tokenVersion) {
      // Token was issued before a password change / forced logout.
      return res.status(401).json({ error: "Session expired, please log in again." });
    }

    req.user = user;
    next();
  } catch (err) {
    return res.status(401).json({ error: "Invalid or expired token." });
  }
}

function requireRole(...roles) {
  return (req, res, next) => {
    if (!req.user || !roles.includes(req.user.role)) {
      return res.status(403).json({ error: "You do not have permission to perform this action." });
    }
    next();
  };
}

module.exports = { requireAuth, requireRole };