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.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

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

Beyond .env: Secrets Managers in Production

.env files solve secrets management for local development — they keep credentials out of source control on your laptop. They do not solve it in production. A .env file sitting on a server is a plaintext file with no access control, no rotation, and no audit trail: anyone who can read the filesystem (a misconfigured backup, a debug endpoint that shells out, a compromised dependency) reads every secret at once.

Production systems fetch secrets from a dedicated secrets manager at startup instead of a file:

typescript
typescript

HashiCorp Vault is the equivalent for teams not on AWS — same idea, different client (node-vault), with the added benefit of short-lived, automatically-rotated credentials (a database password that expires in an hour instead of living in a file forever).

What this buys you over .env in production:

  • Access control — IAM/Vault policies decide who can read which secret, not filesystem permissions.
  • Rotation — rotate a compromised credential without redeploying every service that reads a .env file.
  • Audit trail — every read is logged: which service, which secret, when.

.env for local dev, a secrets manager for anything deployed — they're two halves of the same practice, not competing approaches.


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

CSP exists to restrict what a browser rendering your response as HTML is allowed to load and execute. A pure JSON API never asks a browser to render its response as HTML, so CSP has nothing to protect there — it's not a matter of "relaxing" the directives, it's that the entire header is largely moot. (A directive list that just restates self for every source — as an earlier version of this section showed — isn't looser than Helmet's own default policy; it's the same policy with fewer entries typed out.)

For a pure JSON API, pick one of two honest options instead of a fake "relaxed" config:

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

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