/** * authMiddleware.js — JWT sign/verify helpers + Express middleware for Curio HMS. */ const jwt = require('jsonwebtoken'); const JWT_SECRET = process.env.JWT_SECRET || 'curio_dev_secret_change_in_production'; const JWT_EXPIRY = '7d'; /** * Sign a JWT with the given payload. * @param {{ userId, email, role, tenantId }} payload * @returns {string} signed JWT */ function signToken(payload) { return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRY }); } /** * Express middleware: verifies JWT and enforces role access. * @param {...string} roles - allowed roles; empty = any authenticated user */ function requireAuth(...roles) { return (req, res, next) => { const header = req.headers['authorization'] || req.headers['x-auth-token']; if (!header) return res.status(401).json({ error: 'Authentication required' }); const token = header.startsWith('Bearer ') ? header.slice(7) : header; try { const decoded = jwt.verify(token, JWT_SECRET); req.user = decoded; if (roles.length > 0 && !roles.includes(decoded.role)) { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); } catch (err) { return res.status(401).json({ error: 'Invalid or expired token' }); } }; } /** * Middleware: verifies JWT but does NOT reject unauthenticated requests. * Attaches req.user if valid token present. */ function optionalAuth(req, res, next) { const header = req.headers['authorization'] || req.headers['x-auth-token']; if (header) { const token = header.startsWith('Bearer ') ? header.slice(7) : header; try { req.user = jwt.verify(token, JWT_SECRET); } catch (_) { /* ignore */ } } next(); } module.exports = { signToken, requireAuth, optionalAuth };