const jwt = require('jsonwebtoken');
// Middleware to check if reauthentication is required
function requireReauthentication(maxAge = 15 * 60 * 1000) { // 15 minutes default
return async (req, res, next) => {
try {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({
code: 401,
msg: 'No token provided'
});
}
// Decode token without verification to check timestamp
const decoded = jwt.decode(token);
if (!decoded) {
return res.status(401).json({
code: 401,
msg: 'Invalid token format'
});
}
const tokenAge = Date.now() - (decoded.iat * 1000);
if (tokenAge > maxAge) {
return res.status(403).json({
code: 403,
msg: 'Reauthentication required',
details: 'Token is too old for sensitive operations'
});
}
// Check if user has recently reauthenticated
const reauthKey = `reauth:${decoded.sub}`;
const reauthTimestamp = await redis.get(reauthKey);
if (!reauthTimestamp || (Date.now() - parseInt(reauthTimestamp)) > maxAge) {
return res.status(403).json({
code: 403,
msg: 'Reauthentication required',
details: 'Recent identity verification required'
});
}
next();
} catch (error) {
res.status(500).json({
code: 500,
msg: 'Internal server error'
});
}
};
}
// Reauthentication endpoint handler
app.get('/reauthenticate', authenticateToken, async (req, res) => {
try {
const userId = req.user.sub;
const now = Date.now();
// Store reauthentication timestamp
const reauthKey = `reauth:${userId}`;
await redis.setex(reauthKey, 15 * 60, now.toString()); // 15 minutes TTL
res.json({
message: 'Reauthentication successful',
timestamp: new Date(now).toISOString(),
valid_until: new Date(now + 15 * 60 * 1000).toISOString()
});
} catch (error) {
res.status(500).json({
code: 500,
msg: 'Internal server error'
});
}
});
// Usage on sensitive routes
app.put('/user/password',
authenticateToken,
requireReauthentication(10 * 60 * 1000), // 10 minutes for password change
async (req, res) => {
// Handle password change
res.json({ message: 'Password updated successfully' });
}
);
app.delete('/user/account',
authenticateToken,
requireReauthentication(5 * 60 * 1000), // 5 minutes for account deletion
async (req, res) => {
// Handle account deletion
res.json({ message: 'Account deleted successfully' });
}
);