5.1 KiB
5.1 KiB
Backend Middleware
Middleware components provide cross-cutting concerns for authentication, authorization, validation, rate limiting, and error handling across all API endpoints.
Middleware Architecture
Express middleware functions are composed in the request pipeline to:
- Authenticate users via JWT tokens
- Authorize access based on user roles
- Validate request bodies against Zod schemas
- Apply rate limits to prevent abuse
- Handle errors consistently
- Log requests and responses
Core Middleware
Authentication
authenticate (middleware/auth.ts)
- Verifies JWT access tokens from Authorization header
- Attaches
req.userobject with user ID, email, and role - Returns 401 Unauthorized for missing/invalid tokens
- Supports both admin and public route protection
router.get('/profile', authenticate, async (req, res) => {
// req.user is guaranteed to exist
const userId = req.user.id;
});
Authorization
requireRole (middleware/auth.ts)
- Checks if authenticated user has one of the required roles
- Returns 403 Forbidden if role check fails
- Supports multiple roles (OR logic)
router.post(
'/campaigns',
authenticate,
requireRole('SUPER_ADMIN', 'INFLUENCE_ADMIN'),
async (req, res) => {
// Only admins can create campaigns
}
);
requireNonTemp (middleware/auth.ts)
- Blocks TEMP users from accessing endpoints
- Used for routes that require full user accounts
- TEMP users are created during shift signups
router.post(
'/shifts/:id/signup',
authenticate,
requireNonTemp,
async (req, res) => {
// TEMP users cannot sign up for shifts
}
);
Validation
validate (middleware/validate.ts)
- Validates request body against Zod schemas
- Returns 400 Bad Request with sanitized error messages
- Supports nested validation and type coercion
- Prevents injection attacks by sanitizing output
import { validate } from '../middleware/validate';
import { createCampaignSchema } from './campaigns.schemas';
router.post(
'/campaigns',
authenticate,
validate(createCampaignSchema),
async (req, res) => {
// req.body is type-safe and validated
}
);
Rate Limiting
rateLimit (middleware/rate-limit.ts)
- Uses Redis for distributed rate limiting
- Configurable window size and max requests
- Returns 429 Too Many Requests when limit exceeded
- Per-IP tracking with X-RateLimit headers
Common Configurations:
// Auth endpoints: 10 requests per minute
rateLimitRedis({
windowMs: 60 * 1000,
max: 10,
standardHeaders: true,
legacyHeaders: false,
keyPrefix: 'rl:auth:',
})
// Canvass visits: 30 requests per minute
rateLimitRedis({
windowMs: 60 * 1000,
max: 30,
keyPrefix: 'rl:canvass-visit:',
})
Error Handling
errorHandler (middleware/error-handler.ts)
- Catches all unhandled errors in routes
- Formats errors consistently as JSON
- Logs errors with Winston
- Sanitizes error messages in production
- Returns appropriate HTTP status codes
Request Logging
requestLogger (middleware/logger.ts)
- Logs all incoming requests with Morgan
- Tracks response times
- Formats logs with Winston
- Separates error logs from access logs
Middleware Composition
Middleware is applied in order and can be composed:
// Global middleware (applies to all routes)
app.use(helmet());
app.use(cors());
app.use(requestLogger);
// Route-specific middleware
router.post(
'/api/campaigns',
rateLimit({ max: 100 }),
authenticate,
requireRole('SUPER_ADMIN', 'INFLUENCE_ADMIN'),
validate(createCampaignSchema),
campaignController.create
);
// Global error handler (last middleware)
app.use(errorHandler);
Security Features
Password Policy
- Enforced at schema validation level
- 12+ characters required
- Must include uppercase, lowercase, and digit
- Validated in
auth.schemas.ts
User Enumeration Prevention
- Returns 401 instead of 404 for missing users
- Consistent response times for invalid credentials
- No detailed error messages about which field failed
Refresh Token Rotation
- Atomic transaction to prevent race conditions
- Invalidates old refresh token on rotation
- Tracks token family for security
- Automatic cleanup of expired tokens
Redis Authentication
- All Redis connections require password
- Configured via
REDIS_PASSWORDenvironment variable - Prevents unauthorized cache/queue access
Middleware Chain
Typical middleware chain for protected routes:
- CORS - Handle cross-origin requests
- Helmet - Security headers
- Request Logger - Log incoming request
- Body Parser - Parse JSON body
- Rate Limit - Check rate limits
- Authenticate - Verify JWT token
- Authorize - Check user role
- Validate - Validate request schema
- Route Handler - Execute business logic
- Error Handler - Catch and format errors