// FILE: backend/src/middleware/auth.js import jwt from "jsonwebtoken"; import { config } from "../config.js"; import { User, Role, UserRole } from "../db/sequelize.js"; export function signAccessToken(payload) { return jwt.sign(payload, config.JWT.SECRET, { expiresIn: config.JWT.EXPIRES_IN, }); } export function signRefreshToken(payload) { return jwt.sign(payload, config.JWT.REFRESH_SECRET, { expiresIn: config.JWT.REFRESH_EXPIRES_IN, }); } export function extractToken(req) { // ให้คุกกี้มาก่อน แล้วค่อย Bearer (รองรับทั้งสองทาง) const cookieTok = req.cookies?.access_token || null; if (cookieTok) return cookieTok; const hdr = req.headers.authorization || ""; return hdr.startsWith("Bearer ") ? hdr.slice(7) : null; } export function requireAuth(req, res, next) { if (req.path === "/health") return next(); // อนุญาต health เสมอ const token = extractToken(req); if (!token) return res.status(401).json({ error: "Missing token" }); try { req.user = jwt.verify(token, config.JWT.SECRET); next(); } catch { return res.status(401).json({ error: "Invalid/Expired token" }); } } // ใช้กับเส้นทางที่ login แล้วจะ enrich ต่อได้ แต่ไม่บังคับ export function optionalAuth(req, _res, next) { const token = extractToken(req); if (!token) return next(); try { req.user = jwt.verify(token, config.JWT.SECRET); } catch {} next(); } export async function enrichRoles(req, _res, next) { if (!req.user?.user_id) return next(); const rows = await UserRole.findAll({ where: { user_id: req.user.user_id }, include: [{ model: Role }], }).catch(() => []); req.user.roles = rows.map((r) => r.role?.role_name).filter(Boolean); next(); } export function hasPerm(req, perm) { const set = new Set(req?.user?.permissions || []); return set.has(perm); }