Managing Secrets

Out of Code, Out of Git, In Memory Only

Managing Secrets

Secrets — DB URLs, API keys, JWT secrets — never go in git. Use env vars, secret managers, and rotation.

3 min read Level 1/5 #express#secrets#security
What you'll learn
  • Use env vars correctly
  • Pick a secret manager
  • Rotate compromised secrets immediately

The single most common production incident: someone committed a secret to git. Don’t be that someone.

Rules

  1. Never commit .env files
  2. Always add .env* to .gitignore
  3. Always check git history before pushing
  4. Rotate immediately if a secret leaked — even once

.gitignore

# .gitignore
.env
.env.*
!.env.example

The !.env.example pattern keeps an example committed (template of expected vars).

A .env.example

# .env.example
PORT=3000
NODE_ENV=development
DATABASE_URL=
JWT_SECRET=
SESSION_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

Empty values. Devs copy this to .env and fill in.

Load With Node 22+

node --env-file=.env src/index.js

Or via dotenv:

import "dotenv/config";

console.log(process.env.JWT_SECRET);

Validate at Boot

Crash fast at startup beats crashing mid-request:

// src/config/env.js
import { z } from "zod";

const Schema = z.object({
  PORT:             z.coerce.number().int().default(3000),
  NODE_ENV:         z.enum(["development", "test", "production"]).default("development"),
  DATABASE_URL:     z.string().url(),
  JWT_SECRET:       z.string().min(32),
  SESSION_SECRET:   z.string().min(32),
});

export const env = Schema.parse(process.env);

If a required var is missing, the app refuses to start.

Real Production

Env files are fine for dev. For production:

PlatformSecret store
Heroku / Render / FlyBuilt-in env-var UI
AWSSecrets Manager or Parameter Store
GCPSecret Manager
AzureKey Vault
Self-hostedHashiCorp Vault, Doppler, Infisical
KubernetesSealed Secrets, External Secrets Operator

Pull at startup, never bake into images.

When A Secret Leaks

It’s not “if” — it’s “when.” Have a plan:

  1. Rotate immediately — invalidate the old secret
  2. Audit usage — was the old secret actually used?
  3. Force re-issue for downstream consumers
  4. Document the incident

For DB credentials, JWT secrets, and OAuth client secrets — rotation is straightforward. Plan for it. Practice once before you need it.

Never Log Secrets

The fastest way to leak a secret is a stack trace in your logs:

console.log(`connecting with ${process.env.DATABASE_URL}`);   // 🚨

Even structured logs ship to log services. Mask sensitive values. Most secret managers warn on leaked values; configure them.

End of Chapter

Auth and security done. Next chapter: data — databases, ORMs, uploads, streaming, queues.

Database Integration →