Authorization and RBAC
Implement Role-Based Access Control.
Authorization Middleware
typescript
// src/middlewares/auth.middleware.tsexport const authorize = (...roles: string[]) => { return (req: Request, res: Response, next: NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Not authenticated' }); } if (!roles.includes(req.user.role)) { return res.status(403).json({ error: 'Access denied' }); } next(); };};Usage in Routes
typescript
// Only ADMIN can accessrouter.post('/products', authenticate, authorize('ADMIN'), controller.store); // USER and ADMIN can accessrouter.get('/orders', authenticate, authorize('USER', 'ADMIN'), controller.index);Permissions System
typescript
// src/config/permissions.tsexport const permissions = { ADMIN: [ 'products:create', 'products:update', 'products:delete', 'orders:manage', 'users:manage' ], USER: [ 'products:read', 'orders:create', 'orders:read' ]}; export const can = (role: string, permission: string): boolean => { return permissions[role]?.includes(permission) ?? false;};typescript
// Middlewareexport const requirePermission = (permission: string) => { return (req: Request, res: Response, next: NextFunction) => { if (!can(req.user!.role, permission)) { return res.status(403).json({ error: 'Access denied' }); } next(); };}; // Usagerouter.delete('/products/:id', authenticate, requirePermission('products:delete'), controller.destroy);Resource Ownership
typescript
// Only access own ordersexport const ownsResource = (resourceUserId: string, currentUserId: string, role: string) => { if (role === 'ADMIN') return true; return resourceUserId === currentUserId;}; // In serviceasync findUserOrders(userId: string, currentUser: { id: string; role: string }) { if (!ownsResource(userId, currentUser.id, currentUser.role)) { throw new AppError('Access denied', 403); } return prisma.order.findMany({ where: { userId } });}Summary
- ✅ Role-based authorization
- ✅ Granular permissions
- ✅ Resource ownership control
Next lesson: File Upload! 🚀