Module P-6·22 min read

12-factor app config, Helmet security headers, express-rate-limit, CORS, HTTPS enforcement, secure cookie flags, and secrets management patterns.

Module P-6 — Configuration, Security Hardening, and Rate Limiting

What this module covers: An API that works on your machine is not a production API. This module covers the 12-factor approach to configuration so secrets never end up in source control, the HTTP security headers that close the most common attack vectors, CORS configured correctly so browsers can reach your API, rate limiting that stops brute-force attacks, and the secure cookie flags that protect tokens from XSS. These are not optional polish — they are the baseline that separates hobby projects from production systems.


12-Factor Configuration: No Secrets in Code

The Twelve-Factor App methodology's rule on configuration: store config in the environment, never in the code. Every value that changes between environments (dev, staging, production) is configuration. Every credential is configuration.

bash

dotenv for local development

bash
bash
bash
bash

Load dotenv once, at the very start of your application:

typescript

Config validation with Zod

Raw process.env is untyped — every value is string | undefined. Validate it at startup so the app fails fast with a clear error instead of silently failing later:

typescript

Import env instead of process.env everywhere:

typescript

Helmet: HTTP Security Headers

Helmet sets HTTP response headers that tell browsers how to handle your content safely. It prevents a class of attacks that have nothing to do with your application logic.

bash
typescript

That one line sets these headers (among others):

HeaderWhat it does
Content-Security-PolicyRestricts which resources the browser can load — blocks inline script injection
X-Frame-OptionsPrevents clickjacking (your page can't be embedded in an iframe)
X-Content-Type-Options: nosniffPrevents MIME type sniffing — browser uses declared content type
Strict-Transport-SecurityForces HTTPS for future requests (HSTS)
Referrer-PolicyControls how much URL info is sent in the Referer header
X-Permitted-Cross-Domain-PoliciesBlocks Adobe Flash/Acrobat cross-domain requests

For APIs returning JSON, you can relax the CSP since there is no HTML to protect:

typescript

CORS: Cross-Origin Resource Sharing

Browsers block cross-origin requests by default. CORS is the mechanism that lets your API tell browsers which origins are allowed.

bash

The wrong way — a development shortcut that leaks into production:

typescript

The right way — explicit allow list:

typescript

In .env:

bash

Preflight requests: Before sending a non-simple request (POST with JSON, any DELETE, any custom header), browsers send an OPTIONS preflight to ask permission. Helmet and the cors package handle this automatically. If you see OPTIONS requests failing, check that your CORS config allows the method and headers being used.


Rate Limiting

Without rate limiting, a single client can flood your auth endpoints with thousands of login attempts per second. Rate limiting is the first line of defense against brute force, credential stuffing, and denial-of-service.

bash

Global rate limit — apply to all routes:

typescript

Stricter limits for auth endpoints:

typescript

Apply globally first, then stricter limits on specific routes:

typescript

Rate limiting with Redis (for multi-server deployments):

The default in-memory store does not share state across processes. If you have two app servers, each has its own counter — a client gets 2× the allowed requests. Use Redis for a shared store:

bash
typescript

When storing refresh tokens in HTTP-only cookies (recommended over response body), these flags are non-negotiable:

typescript

Install cookie-parser to read cookies:

bash
typescript
FlagWhat it prevents
httpOnlyXSS — attacker's injected script can't read the token
secureToken transmitted over cleartext HTTP
sameSite: strictCSRF — browser doesn't send the cookie on cross-site requests
path: '/auth'Token sent on every request, not just auth endpoints

Additional Security Practices

Disable the X-Powered-By header — don't advertise your stack:

typescript

Sanitise MongoDB/NoSQL injection (if using MongoDB):

bash
typescript

Request size limits — prevent large payloads from exhausting memory:

typescript

HTTPS in production — your app should run behind a TLS-terminating reverse proxy (nginx, Cloudflare, AWS ALB). The app itself typically serves HTTP internally. If you need HTTPS at the app level:

typescript

Putting It Together: Security Middleware Stack

The order matters — helmet and rate limiters should run before routes:

typescript

Summary

  • 12-factor config: all env-specific values in environment variables, validated with Zod at startup, never in code.
  • Helmet: one line that sets a dozen security headers — Content-Security-Policy, X-Frame-Options, HSTS, and more. Always use it.
  • CORS: explicit origin allow list from environment variables. Never cors() with no options in production.
  • Rate limiting: global limiter for all routes, stricter limiter on auth endpoints. Use Redis store when running multiple servers.
  • HTTP-only cookies: store refresh tokens in httpOnly; Secure; SameSite=Strict cookies with a scoped path — the trifecta that blocks XSS, HTTPS downgrade, and CSRF.
  • Request size limits: express.json({ limit: '10kb' }) prevents memory exhaustion from large payloads.

Next: connecting external services — Redis caching with the cache-aside pattern, sending email, uploading files to object storage, and making outbound HTTP requests to third-party APIs.


Knowledge Check

What is the Twelve-Factor App methodology's rule regarding configuration management?


Why is it dangerous to simply use app.use(cors()) without passing any options in a production environment?


When storing a refresh token in a cookie, which flag is responsible for ensuring that malicious JavaScript (XSS) cannot read the token?

Test your knowledge with more question sets

Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.