ideas-generator/server/middleware/auth.js
DJP 013f57fe60 Implement hybrid Azure AD SSO + Password authentication system
 Backend Implementation:
- Add Azure AD JWT token validation middleware
- Create hybrid authentication system supporting both Azure AD and password auth
- Implement auto-provisioning for new Azure AD users
- Add admin controls to toggle password authentication
- Update all API routes to use hybrid authentication
- Add database fields for authentication (password, lastLoginAt)
- Create comprehensive auth routes with validation endpoints

 Frontend Implementation:
- Install and configure Azure MSAL browser library
- Create Azure AD authentication service with popup/redirect support
- Build hybrid authentication service managing both auth methods
- Update Login.vue with modern dual-authentication UI
- Implement dynamic password auth toggle based on admin settings
- Update App.vue for proper session management and validation
- Modify API service to handle both token types

 Security Features:
- Azure AD tenant validation (Oliver Agency)
- Role-based access control with auto-admin assignment
- JWT token validation for both auth methods
- Automatic user provisioning with proper defaults
- Session validation and automatic logout on token expiry

 Admin Features:
- Toggle password authentication on/off
- Manage users from both authentication methods
- Full role and agent access control
- Azure AD user auto-provisioning as regular users

 Configuration:
- Azure AD: Tenant e519c2e6-bc6d-4fdf-8d9c-923c2f002385
- Client ID: 9079054c-9620-4757-a256-23413042f1ef
- Development redirect URI support
- Fallback password authentication for testing

🔧 Technical Stack:
- Azure MSAL Browser & Node libraries
- JWT token validation and hybrid middleware
- Database schema updates with migrations
- Vue.js integration with MSAL
- Express.js hybrid authentication routes

🚀 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-09 16:14:02 -04:00

68 lines
No EOL
1.8 KiB
JavaScript

const jwt = require('jsonwebtoken');
const User = require('../models/User');
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-change-in-production';
const authenticateToken = async (req, res, next) => {
try {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ message: 'Access token required' });
}
const decoded = jwt.verify(token, JWT_SECRET);
// Get user from database to ensure they still exist and are active
const user = await User.findByPk(decoded.id);
if (!user || !user.isActive) {
return res.status(403).json({ message: 'User not found or inactive' });
}
req.user = {
id: user.id,
email: user.email,
name: user.name,
role: user.preferences?.role || 'user',
allowedAgents: user.preferences?.allowedAgents || null
};
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(403).json({ message: 'Token expired' });
}
if (error.name === 'JsonWebTokenError') {
return res.status(403).json({ message: 'Invalid token' });
}
return res.status(500).json({ message: 'Token verification failed' });
}
};
const requireAdmin = (req, res, next) => {
if (!req.user || req.user.role !== 'admin') {
return res.status(403).json({ message: 'Admin privileges required' });
}
next();
};
const generateToken = (user) => {
return jwt.sign(
{
id: user.id,
email: user.email,
role: user.preferences?.role || 'user'
},
JWT_SECRET,
{ expiresIn: '24h' }
);
};
module.exports = {
authenticateToken,
requireAdmin,
generateToken,
JWT_SECRET
};