Merge pull request 'Fail fast when JWT_SECRET is missing in production (closes #14)' (#21) from fix/jwt-secret-fail-fast into main

Reviewed-on: UOM/website#21
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
2026-07-03 05:58:16 +00:00

View File

@@ -4,16 +4,27 @@ require('dotenv').config()
const log = require('./logger')('auth') const log = require('./logger')('auth')
const users = require('../model/users/users.model') const users = require('../model/users/users.model')
const JWT_SECRET = process.env.JWT_SECRET
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '1d' const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '1d'
const COOKIE_NAME = process.env.COOKIE_NAME || 'uomm_token' const COOKIE_NAME = process.env.COOKIE_NAME || 'uomm_token'
// Lifetime of the short-lived "password verified, awaiting TOTP" token. // Lifetime of the short-lived "password verified, awaiting TOTP" token.
const TOTP_CHALLENGE_TTL = process.env.TOTP_CHALLENGE_TTL || '5m' const TOTP_CHALLENGE_TTL = process.env.TOTP_CHALLENGE_TTL || '5m'
if (!JWT_SECRET) { // Resolve the signing secret. Without one, jwt.sign/verify can't produce or
log.warn('JWT_SECRET is not set — set it in .env before going to production') // validate a usable token, so every login is silently broken. Fail fast in
// production rather than booting into that state; in dev fall back to a known
// insecure secret so login still works locally (with a loud warning).
function resolveJwtSecret() {
const secret = process.env.JWT_SECRET
if (secret) return secret
if (process.env.NODE_ENV === 'production') {
throw new Error('JWT_SECRET must be set in production')
}
log.warn('JWT_SECRET is not set — using an insecure development fallback. Set JWT_SECRET in .env before deploying.')
return 'dev-insecure-jwt-secret-do-not-use-in-production'
} }
const JWT_SECRET = resolveJwtSecret()
function signToken(user) { function signToken(user) {
const payload = { id: user.id, username: user.username, role: user.role } const payload = { id: user.id, username: user.username, role: user.role }
return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN }) return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN })