dev1/backend/shared/requireAuth.js

43 lines
1.5 KiB
JavaScript

// shared/auth/requireAuth.js
import jwt from 'jsonwebtoken';
import pool from '../config/mysqlPool.js';
const { JWT_SECRET, TOKEN_MAX_AGE_MS } = process.env;
const MAX_AGE = Number(TOKEN_MAX_AGE_MS || 0); // 0 = disabled
export async function requireAuth(req, res, next) {
try {
const authz = req.headers.authorization || '';
const token = authz.startsWith('Bearer ') ? authz.slice(7) : '';
if (!token) return res.status(401).json({ error: 'Auth required' });
let payload;
try { payload = jwt.verify(token, JWT_SECRET); }
catch { return res.status(401).json({ error: 'Invalid or expired token' }); }
const userId = payload.id;
const iatMs = (payload.iat || 0) * 1000;
// Absolute max token age (optional, off by default)
if (MAX_AGE && Date.now() - iatMs > MAX_AGE) {
return res.status(401).json({ error: 'Session expired. Please sign in again.' });
}
// Reject tokens issued before last password change
const [rows] = await (pool.raw || pool).query(
'SELECT password_changed_at FROM user_auth WHERE user_id = ? ORDER BY id DESC LIMIT 1',
[userId]
);
const changedAt = rows?.[0]?.password_changed_at || 0;
if (changedAt && iatMs < changedAt) {
return res.status(401).json({ error: 'Session invalidated. Please sign in again.' });
}
req.userId = userId;
next();
} catch (e) {
console.error('[requireAuth]', e?.message || e);
return res.status(500).json({ error: 'Server error' });
}
}