Fail fast when JWT_SECRET is missing in production (#14)
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>
This commit is contained in:
@@ -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 })
|
||||||
|
|||||||
Reference in New Issue
Block a user