Image Upload & Thumbnails Tutorial · Module 10 of 11

Security & Compliance

Add authentication and authorization for image access. Implement audit logging for all operations. Add rate limiting to prevent abuse. Support data retention and deletion compliance. By the end, the service is secure, auditable, and compliant with regulations.

~4–5 hrsAdvancedSecurity focus
← Back to Module 10 overview
What You'll Have at the End

Definition of Done

  • JWT authentication on all endpoints.
  • Authorization: users can only access their own images.
  • Rate limiting: 100 uploads/hour per user, 1000 transforms/hour per user.
  • Audit logging: who uploaded/deleted/accessed image, timestamp, IP address.
  • DELETE /images/:id with immediate S3 cleanup.
  • GDPR compliance: data export endpoint, right to deletion.
  • Threat model document.
The Steps

Build It

STEP 1

Implement authentication and authorization middleware

Install: npm install jsonwebtoken @types/jsonwebtoken

Create src/middleware/auth.ts:

import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

export interface AuthenticatedRequest extends Request {
  user?: { id: string; email: string };
}

export function authMiddleware(
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET || 'secret');
    req.user = decoded as any;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
}

export function ownershipCheck(
  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction
) {
  // Verify image belongs to authenticated user
  // In real implementation, query database to check ownership
  const imageOwnerId = req.params.ownerId;
  if (req.user?.id !== imageOwnerId) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  next();
}