SecurityOctober 5, 2024•8 min read•Verified Production Post

Hardening Full-Stack MERN & Next.js: JWT Rotation, Strict RBAC & Edge Rate Limiting

Comprehensive security playbook for modern web applications. Preventing session hijacking with HTTP-only refresh tokens, enforcing type-safe role-based access control, and mitigating DDoS attacks with sliding-window rate limiters.

Listen to Audio DispatchAI Voice
8 min article overview • Narrated audio
<UB>
Ankit Bhuria
Lead Architect & Agency Founder • National SIH 2024 Winner
Hardening Full-Stack MERN & Next.js: JWT Rotation, Strict RBAC & Edge Rate Limiting
Executive Architecture Takeaways

Comprehensive security playbook for modern web applications. Preventing session hijacking with HTTP-only refresh tokens, enforcing type-safe role-based access control, and mitigating DDoS attacks with sliding-window rate limiters.

Architecture Focus
Security + MERN Stack
Reading Investment
8 Min Breakdown
Testing Standard
100% Production Tested
Reader Controls•

#Introduction: The Vulnerability Landscape

Full-stack applications built on Node.js and Next.js are the backbone of modern web startups, but standard tutorials frequently teach unsafe shortcuts: storing raw JWT tokens in browser localStorage, skipping CORS whitelisting, and trusting unvalidated client JSON payloads.

In this technical breakdown, we walk through our agency's production security protocol for hardening web APIs.


#1. Dual-Token Authentication with Silent Refresh

Storing JWTs in localStorage leaves your application completely vulnerable to Cross-Site Scripting (XSS). If an attacker injects a malicious third-party script, they can read the token and impersonate the user indefinitely.

Our architecture uses a split-token approach:

  • Access Token: Short-lived (15 minutes), stored solely in memory (React context/state).
  • Refresh Token: Long-lived (7 days), stored in an httpOnly, secure, sameSite: 'strict' cookie.
typescript
// Secure Refresh Cookie Configuration
res.cookie('refreshToken', refreshToken, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
  path: '/api/auth/refresh', // Scoped exclusively to refresh route
});

#2. Distributed Sliding-Window Rate Limiting

To protect against brute-force credential stuffing and API abuse, we implement a sliding-window counter backed by Redis:

typescript
import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL!);

export async function checkRateLimit(ip: string, limit = 60, windowSeconds = 60): Promise<boolean> {
  const currentTimestamp = Date.now();
  const windowStart = currentTimestamp - (windowSeconds * 1000);
  const key = `ratelimit:${ip}`;

  const multi = redis.multi();
  multi.zremrangebyscore(key, 0, windowStart);
  multi.zadd(key, currentTimestamp, `${currentTimestamp}:${Math.random()}`);
  multi.zcard(key);
  multi.expire(key, windowSeconds);

  const results = await multi.exec();
  const requestCount = results?.[2]?.[1] as number;

  return requestCount <= limit;
}

#3. Zod-Powered Runtime Ingestion Guardrails

Every incoming API payload must be strictly validated before touching your business logic or database. Any unexpected keys must be stripped immediately.

typescript
// Runtime payload validation
export async function validatePayload<T>(schema: z.ZodSchema<T>, data: unknown): Promise<T> {
  const result = schema.safeParse(data);
  if (!result.success) {
    throw new ValidationError(result.error.flatten());
  }
  return result.data;
}

#Summary Checklist

  • [x] Zero JWTs stored in localStorage.
  • [x] Refresh tokens restricted to httpOnly cookies with SameSite=Strict.
  • [x] Sliding-window rate limiters deployed on all authentication endpoints.
  • [x] Strict Zod schemas sanitizing all external JSON payloads.
Reader Feedback & Reactions
Related Topics & Tech Stack:
UB

Ankit Bhuria

Founder, Upgrader Boy • National SIH 2024 Winner

We design and ship high-performance MERN & Next.js 15 platforms, IoT telematics architectures, and real-time distributed backends for ambitious startups and enterprises.

Continue Reading

More engineering deep-dives from the Upgrader Boy team

View All