/** * Authorization Middleware * * Middleware functions for route protection based on authentication and permissions. */ import { Request, Response, NextFunction } from 'express'; import { authService, type SessionUser } from '../services/authService.js'; import { roleService } from '../services/roleService.js'; import { logger } from '../services/logger.js'; // Extend Express Request to include user info declare global { namespace Express { interface Request { sessionId?: string; user?: SessionUser; accessToken?: string; } } } /** * Middleware to require authentication */ export function requireAuth(req: Request, res: Response, next: NextFunction) { const sessionId = req.headers['x-session-id'] as string || req.cookies?.sessionId; if (!sessionId) { return res.status(401).json({ error: 'Authentication required' }); } // Get session user authService.getSession(sessionId) .then(session => { if (!session) { return res.status(401).json({ error: 'Invalid or expired session' }); } // Check if it's a local user session if ('id' in session.user) { req.sessionId = sessionId; req.user = session.user as SessionUser; req.accessToken = session.accessToken; next(); } else { // OAuth-only session (Jira user without local account) // For now, allow through but user won't have permissions req.sessionId = sessionId; req.accessToken = session.accessToken; next(); } }) .catch(error => { logger.error('Auth middleware error:', error); res.status(500).json({ error: 'Authentication check failed' }); }); } /** * Middleware to require a specific role */ export function requireRole(roleName: string) { return async (req: Request, res: Response, next: NextFunction) => { if (!req.user || !('id' in req.user)) { return res.status(403).json({ error: 'Permission denied' }); } const hasRole = await roleService.userHasRole(req.user.id, roleName); if (!hasRole) { return res.status(403).json({ error: `Role '${roleName}' required` }); } next(); }; } /** * Middleware to require a specific permission */ export function requirePermission(permissionName: string) { return async (req: Request, res: Response, next: NextFunction) => { if (!req.user || !('id' in req.user)) { return res.status(403).json({ error: 'Permission denied' }); } const hasPermission = await roleService.userHasPermission(req.user.id, permissionName); if (!hasPermission) { return res.status(403).json({ error: `Permission '${permissionName}' required` }); } next(); }; } /** * Middleware to check permission (optional, doesn't fail if missing) * Sets req.hasPermission flag */ export function checkPermission(permissionName: string) { return async (req: Request, res: Response, next: NextFunction) => { if (req.user && 'id' in req.user) { const hasPermission = await roleService.userHasPermission(req.user.id, permissionName); (req as any).hasPermission = hasPermission; } else { (req as any).hasPermission = false; } next(); }; } /** * Middleware to require admin role */ export const requireAdmin = requireRole('administrator');