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

Documentation | Elite Events | Philip Rehberger