215 lines
5.1 KiB
Markdown

# 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.user` object with user ID, email, and role
- Returns 401 Unauthorized for missing/invalid tokens
- Supports both admin and public route protection
```typescript
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)
```typescript
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
```typescript
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
```typescript
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:**
```typescript
// 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:
```typescript
// 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_PASSWORD` environment variable
- Prevents unauthorized cache/queue access
## Middleware Chain
Typical middleware chain for protected routes:
1. **CORS** - Handle cross-origin requests
2. **Helmet** - Security headers
3. **Request Logger** - Log incoming request
4. **Body Parser** - Parse JSON body
5. **Rate Limit** - Check rate limits
6. **Authenticate** - Verify JWT token
7. **Authorize** - Check user role
8. **Validate** - Validate request schema
9. **Route Handler** - Execute business logic
10. **Error Handler** - Catch and format errors
## Related Documentation
- [Backend Overview](../index.md)
- [Authentication Module](../modules/auth.md)
- [Security Audit](../../deployment/security.md)
- [Environment Variables](../../deployment/environment-variables.md)
- [Rate Limiting](../../deployment/rate-limiting.md)