Skip to main content
Back to Elite Events

Elite Events Documentation

Technical documentation, guides, and API references for the Elite Events platform.

Security & Integrations/Security Guide

Security Hardening - Implementation Complete

This document outlines the security improvements implemented in the Elite Events application as part of Plan 1: Security Hardening.

Overview

The application has been hardened with the following security measures:

✅ Authorization & Access Control ✅ Input Validation & Sanitization ✅ Rate Limiting ✅ Environment Variable Management ✅ Error Handling & Logging ✅ Security Headers ✅ Protected Sensitive Files


1. Authorization & Access Control

Admin Role Checks

All admin-only endpoints now require the ADMIN role:

  • POST /api/products - Create products
  • PATCH /api/products/[id] - Update products
  • DELETE /api/products/[id] - Delete products
  • POST /api/categories - Create categories
  • POST /api/blog - Create blog posts

Implementation: Uses requireAdminRole() from src/lib/auth-utils.ts

await requireAdminRole(); // Throws error if not admin

User Data Ownership Verification

Cart and Wishlist endpoints verify users only access their own data:

  • GET /api/cart - Fetches only user's items
  • PATCH /api/cart/[id] - Updates only user's cart items
  • DELETE /api/cart/[id] - Deletes only user's cart items
  • GET /api/wishlist - Fetches only user's items
  • POST /api/wishlist - Adds to user's wishlist
  • DELETE /api/wishlist/[id] - Removes from user's wishlist

Implementation: All queries use userId from authenticated session

const userId = session.user.id;
const item = await prisma.cart.findUnique({
  where: { userId_productId: { userId, productId } }
});

Session Configuration

NextAuth is configured with:

  • JWT strategy for token-based authentication
  • Role information included in session token
  • Credentials provider with bcrypt password hashing
  • Automatic password verification on signin

Type Safety: src/types/next-auth.d.ts extends NextAuth types with role field


2. Input Validation & Sanitization

Validation Schemas

All API inputs validated using Zod schemas in src/lib/validation-schemas.ts:

  • createProductSchema - Product creation
  • updateProductSchema - Product updates
  • createCategorySchema - Category creation
  • createBlogPostSchema - Blog post creation
  • addToCartSchema - Cart item additions
  • updateCartItemSchema - Cart quantity updates
  • addToWishlistSchema - Wishlist additions
  • signupSchema - User registration
  • signinSchema - User login

Validation Usage

Every API endpoint validates input before processing:

const validation = validateInput(createProductSchema, body);
if (!validation.success) {
  return NextResponse.json(
    { error: "Validation failed", details: validation.errors },
    { status: 400 }
  );
}

Sanitization Features

  • Email validation with RFC compliance
  • String length limits on all text fields
  • Positive number validation for prices and quantities
  • URL validation for image URLs
  • Required/optional field enforcement

3. Rate Limiting

Rate Limit Utility

File: src/lib/rate-limit.ts

In-memory rate limiting with configurable windows:

// Check rate limit
if (!checkRateLimit(identifier, limit, windowMs)) {
  // Request denied
}

// Get limit info for headers
const info = getRateLimitInfo(identifier, limit);

Rate Limit Presets

  • signup: 5 signups per hour (prevents brute force)
  • moderate: 30 requests per hour
  • standard: 100 requests per 15 minutes (default API)
  • generous: 1000 requests per hour (public endpoints)

Applied Limits

  1. Signup Endpoint (src/app/api/auth/signup/route.ts)

    • Limit: 5 signups per hour per IP
    • Headers returned: X-RateLimit-*, Retry-After
  2. Products API (src/app/api/products/route.ts)

    • Limit: 100 requests per 15 minutes per IP
    • Tracks per-IP to prevent abuse

Response Headers

Rate limited responses include:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 2025-01-15T14:30:00Z
Retry-After: 5 (if limit exceeded)

Note: For production with multiple server instances, migrate to Redis-based rate limiting.


4. Environment Variable Management

Validation

File: src/lib/env.ts

Required environment variables validated at startup:

  • DATABASE_URL - MySQL connection string
  • NEXTAUTH_SECRET - Session signing secret
  • NEXTAUTH_URL - Application URL

Optional variables:

  • NODE_ENV - development/production/test
  • NEXT_PUBLIC_API_URL - API base URL

Environment Template

File: .env.example

Template file with all required and optional variables documented. Copy to .env.local and fill in values:

cp .env.example .env.local
# Edit .env.local with your values

Secrets Protection

.gitignore Updated:

.env
.env.local
.env.*.local
.env.production.local
.env.test.local
.env.development.local

Never commit actual .env files to version control.


5. Error Handling & Logging

Error Handler Utility

File: src/lib/error-handler.ts

Centralized error handling with:

  • AppError class for structured errors
  • Consistent error response format
  • HTTP status code mapping
  • Zod validation error extraction
  • Prisma error handling

Usage:

import { handleError, createError } from "@/lib/error-handler";

try {
  // ... endpoint logic
} catch (error) {
  return handleError(error);
}

Logger Utility

File: src/lib/logger.ts

Simple logging with consistent timestamps:

import { logger } from "@/lib/logger";

logger.info("AUTH", "User signed in", { userId });
logger.error("DB", "Query failed", error);
logger.warn("RATE_LIMIT", "Limit approaching", { remaining: 5 });

Available functions:

  • logInfo(context, message, data) - Info level logs
  • logWarn(context, message, data) - Warning level logs
  • logError(context, message, error) - Error level logs
  • logDebug(context, message, data) - Debug logs (dev only)
  • logRequest(method, path, status, userId, duration)
  • logAuth(event, email, success)

6. Security Headers

Security Headers Utility

File: src/lib/security-headers.ts

Headers applied to prevent:

  • MIME Sniffing: X-Content-Type-Options: nosniff
  • Clickjacking: X-Frame-Options: DENY
  • XSS Attacks: X-XSS-Protection: 1; mode=block
  • Referrer Leaks: Referrer-Policy: strict-origin-when-cross-origin
  • HTTPS Downgrade: Strict-Transport-Security (production only)

CORS Configuration

  • Access-Control-Allow-Origin: Set to NEXTAUTH_URL
  • Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
  • Access-Control-Allow-Headers: Content-Type, Authorization
  • Access-Control-Allow-Credentials: true

Implementation

Headers applied to API responses:

const response = NextResponse.json(data);
return addSecurityHeaders(response);

Status: Applied to:

  • ✅ /api/products (GET, POST)
  • ✅ /api/categories (GET, POST)
  • 🔄 Remaining routes (see recommendations below)

Setup Instructions

1. Environment Configuration

# Copy environment template
cp .env.example .env.local

# Generate NextAuth secret
openssl rand -base64 32

# Update .env.local with:
# - DATABASE_URL: Your MySQL connection string
# - NEXTAUTH_SECRET: Generated secret above
# - NEXTAUTH_URL: http://localhost:3000 (or your domain)

2. Database Setup

# Run migrations
npx prisma migrate dev

# Seed database
npx prisma db seed

3. Create Admin User

# Use Prisma Studio to create admin user
npx prisma studio

# Or create via API (requires manual database setup first)
POST /api/auth/signup
{
  "email": "admin@example.com",
  "password": "securepassword",
  "name": "Admin User"
}

# Then manually set role to ADMIN in database
UPDATE users SET role = 'ADMIN' WHERE email = 'admin@example.com';

4. Test Security Features

# Test rate limiting (signup endpoint)
for i in {1..6}; do
  curl -X POST http://localhost:3000/api/auth/signup \
    -H "Content-Type: application/json" \
    -d '{"email":"test'$i'@example.com","password":"password123","name":"Test"}'
done
# 6th request should return 429 Too Many Requests

# Test authorization (non-admin tries to create product)
curl -X POST http://localhost:3000/api/products \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"title":"Product","price":100,...}'
# Should return 403 Forbidden

Recommendations for Production

1. Rate Limiting at Scale

Current implementation uses in-memory rate limiting. For production with multiple instances:

Option 1: Redis

npm install redis

Create src/lib/rate-limit-redis.ts:

import { Redis } from "@upstash/redis";

const redis = new Redis({
  url: process.env.REDIS_URL!,
  token: process.env.REDIS_TOKEN!,
});

export async function checkRateLimitRedis(identifier: string, limit: number, windowMs: number) {
  const key = `ratelimit:${identifier}`;
  const current = await redis.incr(key);

  if (current === 1) {
    await redis.expire(key, Math.ceil(windowMs / 1000));
  }

  return current <= limit;
}

2. Apply Security Headers to All Routes

Add security headers to remaining API routes:

  • /api/products/[id] (GET, PATCH, DELETE)
  • /api/cart/[id] (PATCH, DELETE)
  • /api/wishlist (GET, POST)
  • /api/wishlist/[id] (DELETE)
  • /api/blog (GET, POST)
  • All other API routes

Pattern: Import addSecurityHeaders and wrap all responses

3. Structured Logging

For production, integrate with logging service:

// Replace console.log with service like:
// - Winston (npm install winston)
// - Pino (npm install pino)
// - Datadog
// - LogRocket

4. Error Monitoring

Integrate error tracking:

import * as Sentry from "@sentry/nextjs";

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
});

5. Environment-Specific Headers

For CORS in production, be more restrictive:

const origin = process.env.NODE_ENV === "production"
  ? "https://yourdomain.com"
  : "http://localhost:3000";

return addSecurityHeaders(response, { origin });

6. Database Credentials

For production:

  • Use IAM roles instead of password authentication
  • Restrict database user to specific IPs
  • Use minimum required permissions
  • Enable SSL/TLS for connections

7. Regular Security Audits

# Audit dependencies
npm audit
npm audit fix

# Scan for vulnerabilities
npx snyk test

Testing Checklist

  • Non-admin cannot create products (403)
  • Non-admin cannot edit products (403)
  • Non-admin cannot delete products (403)
  • Admin can create/edit/delete products (200)
  • User cannot access other user's cart (403)
  • Invalid product data rejected (400)
  • Missing required fields rejected (400)
  • 5 signups per hour enforced (429)
  • Rate limit headers returned correctly
  • Security headers present on all responses
  • Sensitive error messages not exposed
  • Environment variables validated at startup

Common Vulnerabilities Fixed

VulnerabilityFixStatus
Broken Access ControlAdmin role checks, user data ownership✅
Injection AttacksInput validation with Zod✅
API AbuseRate limiting✅
Sensitive Data ExposureEnvironment variables, error handling✅
Missing Security HeadersAdded all recommended headers✅
Weak AuthenticationNextAuth with bcrypt, JWT✅
Insufficient LoggingLogger utility with context✅
Unhandled ErrorsError handler utility✅

Files Modified/Created

New Files

  • src/lib/auth-utils.ts - Auth utilities
  • src/lib/validation-schemas.ts - Input validation
  • src/lib/rate-limit.ts - Rate limiting
  • src/lib/env.ts - Environment validation
  • src/lib/error-handler.ts - Error handling
  • src/lib/logger.ts - Logging utility
  • src/lib/security-headers.ts - Security headers
  • src/types/next-auth.d.ts - NextAuth types
  • .env.example - Environment template

Modified Files

  • src/app/api/auth/signup/route.ts - Added rate limiting
  • src/app/api/products/route.ts - Added rate limiting & headers
  • src/app/api/products/[id]/route.ts - Admin checks
  • src/app/api/categories/route.ts - Added headers
  • src/app/api/blog/route.ts - Admin checks
  • src/app/api/cart/route.ts - User ownership checks
  • src/app/api/cart/[id]/route.ts - User ownership checks
  • src/app/api/wishlist/route.ts - User ownership checks
  • src/app/api/wishlist/[id]/route.ts - User ownership checks
  • .gitignore - Explicit env file patterns

Support & Questions

For security concerns or vulnerability reports, refer to the main README.md and CLAUDE.md for contribution guidelines.

Last Updated: 2025-01-19 Plan Status: ✅ Phase 1 Complete