Fail fast when JWT_SECRET is missing in production (closes #14) #21

Merged
whitlocktech merged 1 commits from fix/jwt-secret-fail-fast into main 2026-07-03 05:58:18 +00:00
Member

Summary

Fixes #14 - the server previously booted with no JWT_SECRET, only logging a warning. Without a secret, jwt.sign/jwt.verify can't produce or validate a usable token, so every login silently fails while the process still reports healthy - and running a production instance with no configured secret is a real safety hazard.

Change

server/src/utils/auth.js now resolves the secret through a small resolveJwtSecret() helper instead of just warning:

  • Production (NODE_ENV=production) ? throw JWT_SECRET must be set in production. The process refuses to start rather than booting into an unusable, unsafe state (fail fast).
  • Dev / anything else ? fall back to a known insecure dev secret so local login keeps working, with a loud log.warn telling you to set JWT_SECRET before deploying.

This keeps the friction-free local dev experience (no .env required to click around) while making a misconfigured production deploy impossible to miss.

Why this approach

The issue offered "fail fast in prod" or "always throw". I went with fail-fast-in-prod + explicit dev fallback because:

  • Login actually works in dev now. Before, an unset secret meant jwt.verify threw on every request - login was silently broken even locally. The old warning didn't fix that; a real fallback value does.
  • Production is protected by the hard throw, which is the case the issue actually cares about.

Testing

  • node --check server/src/utils/auth.js - passes.
  • Logic review:
    • JWT_SECRET set ? used as-is (unchanged behavior).
    • unset + NODE_ENV=production ? throws at startup.
    • unset + dev ? insecure fallback + warning, login functional.

Notes

  • server/.env.example already ships JWT_SECRET=dev-only-change-me, so the documented dev setup is unaffected.
  • No API or route changes; internal-only hardening.

?? Generated with Claude Code

## Summary Fixes #14 - the server previously **booted with no `JWT_SECRET`**, only logging a warning. Without a secret, `jwt.sign`/`jwt.verify` can't produce or validate a usable token, so **every login silently fails** while the process still reports healthy - and running a production instance with no configured secret is a real safety hazard. ## Change `server/src/utils/auth.js` now resolves the secret through a small `resolveJwtSecret()` helper instead of just warning: - **Production (`NODE_ENV=production`)** ? **throw** `JWT_SECRET must be set in production`. The process refuses to start rather than booting into an unusable, unsafe state (fail fast). - **Dev / anything else** ? fall back to a known **insecure** dev secret so local login keeps working, with a loud `log.warn` telling you to set `JWT_SECRET` before deploying. This keeps the friction-free local dev experience (no `.env` required to click around) while making a misconfigured production deploy impossible to miss. ## Why this approach The issue offered "fail fast in prod" or "always throw". I went with fail-fast-in-prod + explicit dev fallback because: - **Login actually works in dev now.** Before, an unset secret meant `jwt.verify` threw on *every* request - login was silently broken even locally. The old warning didn't fix that; a real fallback value does. - Production is protected by the hard `throw`, which is the case the issue actually cares about. ## Testing - `node --check server/src/utils/auth.js` - passes. - Logic review: - `JWT_SECRET` set ? used as-is (unchanged behavior). - unset + `NODE_ENV=production` ? throws at startup. - unset + dev ? insecure fallback + warning, login functional. ## Notes - `server/.env.example` already ships `JWT_SECRET=dev-only-change-me`, so the documented dev setup is unaffected. - No API or route changes; internal-only hardening. ?? Generated with [Claude Code](https://claude.com/claude-code)
wtclaude added 1 commit 2026-07-03 05:56:14 +00:00
auth.js previously only logged a warning when JWT_SECRET was unset and
then continued to boot. With no secret, jwt.sign/jwt.verify cannot
produce or validate a usable token, so every login silently fails while
the server appears healthy — and booting a production instance without a
configured secret is a safety hazard.

Resolve the secret through resolveJwtSecret():
  - production (NODE_ENV=production): throw, so the process refuses to
    start without a real secret instead of running unusable.
  - dev/other: fall back to a known insecure secret so local login keeps
    working, with a loud warning to set JWT_SECRET before deploying.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
whitlocktech closed this pull request 2026-07-03 05:56:34 +00:00
whitlocktech deleted branch fix/jwt-secret-fail-fast 2026-07-03 05:56:34 +00:00
whitlocktech reopened this pull request 2026-07-03 05:57:10 +00:00
whitlocktech added the
bug
label 2026-07-03 05:57:17 +00:00
wtclaude was assigned by whitlocktech 2026-07-03 05:57:24 +00:00
whitlocktech approved these changes 2026-07-03 05:58:08 +00:00
whitlocktech merged commit 05933f8d94 into main 2026-07-03 05:58:18 +00:00
whitlocktech deleted branch fix/jwt-secret-fail-fast 2026-07-03 05:58:18 +00:00
Sign in to join this conversation.
No description provided.