215 lines
5.1 KiB
Markdown
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)
|