/** * Copyright (c) 2026 Niolla * All rights reserved. * * This source code is proprietary and confidential. * Unauthorized copying, modification, distribution, or use * of this file, via any medium, is strictly prohibited. */ // app/middleware/auth.middleware.js const { verifyToken } = require("../utils/jwt.util"); const { getEffectivePermissions } = require("../services/permission.service"); const authenticate = async (req, res, next) => { try { let token = null; // Get token from cookie if (req.cookies?.access_token) { token = req.cookies.access_token; } // Fallback to Bearer token if (!token && req.headers.authorization?.startsWith("Bearer ")) { token = req.headers.authorization.split(" ")[1]; } if (!token) { return res.status(401).json({ success: false, message: "Unauthorized", }); } // Verify token const decoded = verifyToken(token); if (process.env.NODE_ENV === "development") { console.log("DECODED:", decoded); } const userId = decoded.sub || decoded.id; if (!userId) { throw new Error("User ID missing in token"); } // Load permissions const permissions = await getEffectivePermissions(userId); req.user = { ...decoded, id: userId, permissions, }; next(); } catch (err) { console.error("AUTH ERROR:", err); // Clear invalid/expired cookie res.clearCookie("access_token", { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: process.env.NODE_ENV === "production" ? "None" : "Lax", }); // Token expired if (err.name === "TokenExpiredError") { return res.status(401).json({ success: false, message: "Session expired. Please login again.", }); } // Invalid token if (err.name === "JsonWebTokenError") { return res.status(401).json({ success: false, message: "Invalid token", }); } // Default return res.status(401).json({ success: false, message: "Authentication failed", }); } }; module.exports = { authenticate };