Files

62 lines
2.0 KiB
JavaScript
Raw Permalink Normal View History

2026-07-01 01:10:13 +05:45
// ============================================================
// authMiddleware.js — JWT + session validation
// ============================================================
// Every protected route runs this middleware first.
// It checks two things:
// 1. Is the JWT signature valid and not expired?
// 2. Does this session (jti) still exist in the sessions table?
// → If "logout all devices" was called, all sessions are
// deleted, so even a valid JWT gets rejected here.
// ============================================================
const jwt = require('jsonwebtoken');
const pool = require('../db');
async function authenticate(req, res, next) {
const token = req.cookies.token;
if (!token) {
return res.status(401).json({ message: 'Not authenticated. Please login.' });
}
try {
// Step 1: Verify JWT signature and expiry
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Step 2: Check this session still exists in the DB
// This is what makes "logout all devices" work —
// deleting sessions from DB invalidates all existing tokens
const session = await pool.query(
'SELECT id FROM sessions WHERE jti = $1',
[decoded.jti]
);
if (session.rows.length === 0) {
return res.status(401).json({ message: 'Session expired or signed out. Please login again.' });
}
// Step 3: Update last_used_at to track device activity
await pool.query(
'UPDATE sessions SET last_used_at = NOW() WHERE jti = $1',
[decoded.jti]
);
req.user = decoded; // { id, username, role, jti }
req.userJti = decoded.jti; // shortcut for logout
next();
} catch (err) {
return res.status(401).json({ message: 'Session expired. Please login again.' });
}
}
// Middleware: Check if the user has admin role
// Must be used AFTER 'authenticate'
function requireAdmin(req, res, next) {
if (req.user.role !== 'admin') {
return res.status(403).json({ message: 'Admin access required.' });
}
next();
}
module.exports = { authenticate, requireAdmin };