WIP: admin auth

This commit is contained in:
Danny Avila 2025-08-30 04:41:51 -04:00
parent d04da60b3b
commit fbe0def2fa
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
8 changed files with 229 additions and 0 deletions

View file

@ -0,0 +1,77 @@
const { logger, signPayload } = require('@librechat/data-schemas');
const { generate2FATempToken } = require('~/server/services/twoFactorService');
const { setAuthTokens } = require('~/server/services/AuthService');
/**
* Generates admin-specific JWT token with isAdmin claim
* @param {Object} user - User object from database
* @returns {Promise<string>} - JWT token
*/
const generateAdminToken = async (user) => {
if (!user) {
throw new Error('No user provided');
}
let expires = 1000 * 60 * 15; // 15 minutes default
if (process.env.SESSION_EXPIRY !== undefined && process.env.SESSION_EXPIRY !== '') {
try {
const evaluated = eval(process.env.SESSION_EXPIRY);
if (evaluated) {
expires = evaluated;
}
} catch (error) {
logger.warn('Invalid SESSION_EXPIRY expression, using default:', error);
}
}
return await signPayload({
payload: {
id: user._id,
username: user.username,
provider: user.provider,
email: user.email,
isAdmin: true, // Admin-specific claim
},
secret: process.env.JWT_SECRET,
expirationTime: expires / 1000,
});
};
/**
* Admin login controller - handles authentication for admin users
* Returns admin-specific JWT with isAdmin claim
*/
const adminLoginController = async (req, res) => {
try {
if (!req.user) {
return res.status(400).json({ message: 'Invalid credentials' });
}
// User role validation is already done in requireAdminAuth middleware
// Handle 2FA if enabled
if (req.user.twoFactorEnabled) {
const tempToken = generate2FATempToken(req.user._id);
return res.status(200).json({ twoFAPending: true, tempToken });
}
const { password: _p, totpSecret: _t, __v, ...user } = req.user;
user.id = user._id.toString();
// Generate admin-specific token
const token = await generateAdminToken(req.user);
// Set standard auth cookies (refreshToken, etc.)
await setAuthTokens(req.user._id, res);
return res.status(200).send({ token, user, isAdmin: true });
} catch (err) {
logger.error('[adminLoginController]', err);
return res.status(500).json({ message: 'Something went wrong' });
}
};
module.exports = {
adminLoginController,
};

View file

@ -0,0 +1,39 @@
const { logger } = require('@librechat/data-schemas');
const { SystemRoles } = require('librechat-data-provider');
/**
* Admin token verification controller
* Verifies JWT token and returns user data if valid and has admin role
* Used by admin panel to verify authentication status
*/
const adminVerifyController = async (req, res) => {
try {
// User is already authenticated via requireAdminJwtAuth middleware
if (!req.user) {
return res.status(401).json({ message: 'Unauthorized' });
}
// Double-check admin role (redundant but ensures security)
if (!req.user.role || req.user.role !== SystemRoles.ADMIN) {
logger.warn('[adminVerifyController] Non-admin user attempting to verify:', req.user.email);
return res.status(403).json({ message: 'Access denied: Admin privileges required' });
}
// Return user data without sensitive fields
const { password: _p, totpSecret: _t, __v, ...user } = req.user;
user.id = user._id.toString();
return res.status(200).json({
valid: true,
user,
isAdmin: true,
});
} catch (err) {
logger.error('[adminVerifyController]', err);
return res.status(500).json({ message: 'Something went wrong' });
}
};
module.exports = {
adminVerifyController,
};