From da645290af217aae39c92dd9a0b3c64269625db3 Mon Sep 17 00:00:00 2001 From: Alexander Borg Date: Sat, 13 Sep 2025 13:25:41 +0200 Subject: [PATCH] Fix jwt-token --- server/routes/user.js | 96 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/server/routes/user.js b/server/routes/user.js index 4b87ab4..de9390a 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -75,7 +75,7 @@ router.post('/register', validateRequest(registerSchema), async (req, res) => { } }); -// POST /api/users/login - User login +// POST /api/users/login - User login (direct API access - for legacy support) router.post('/login', validateRequest(loginSchema), async (req, res) => { try { const { username, password } = req.body; @@ -212,4 +212,98 @@ router.get('/', authenticateToken, requireRole(['admin']), async (req, res) => { } }); +/** + * Tenant-aware local authentication function + * Called by multi-tenant auth middleware + */ +async function loginLocal(req, res, next) { + try { + const { username, password } = req.body; + const { Tenant } = require('../models'); + + // Get tenant information from request (set by multi-tenant auth middleware) + let tenantId = null; + if (req.tenant && req.tenant.id) { + // Find the actual tenant in database + const tenant = await Tenant.findOne({ where: { slug: req.tenant.id } }); + if (tenant) { + tenantId = tenant.id; + } + } + + console.log(`🔐 Login attempt for user "${username}" in tenant "${req.tenant?.id}" (${tenantId})`); + + // Find user by username or email within the specific tenant + const whereClause = { + [Op.and]: [ + { + [Op.or]: [ + { username: username }, + { email: username } + ] + }, + { is_active: true } + ] + }; + + // Add tenant filtering - only include users from this tenant + if (tenantId) { + whereClause[Op.and].push({ tenant_id: tenantId }); + } else { + // For default tenant, look for users with null tenant_id + whereClause[Op.and].push({ tenant_id: null }); + } + + const user = await User.findOne({ where: whereClause }); + + if (!user || !await bcrypt.compare(password, user.password_hash)) { + console.log(`❌ Authentication failed for "${username}" in tenant "${req.tenant?.id}"`); + return res.status(401).json({ + success: false, + message: 'Invalid credentials' + }); + } + + console.log(`✅ Authentication successful for "${username}" in tenant "${req.tenant?.id}"`); + + // Update last login + await user.update({ last_login: new Date() }); + + // Generate JWT token with tenant information + const token = jwt.sign( + { + userId: user.id, + username: user.username, + role: user.role, + tenantId: user.tenant_id, + tenantSlug: req.tenant?.id + }, + process.env.JWT_SECRET, + { expiresIn: '24h' } + ); + + // Remove password hash from response + const { password_hash: _, ...userResponse } = user.toJSON(); + + res.json({ + success: true, + data: { + user: userResponse, + token, + expires_in: '24h' + }, + message: 'Login successful' + }); + + } catch (error) { + console.error('Error during tenant-aware login:', error); + res.status(500).json({ + success: false, + message: 'Login failed', + error: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error' + }); + } +} + module.exports = router; +module.exports.loginLocal = loginLocal;