express-rest-api-boilerplate
express-rest-api-boilerplate copied to clipboard
Feat: JWT_SECRET by default and enforcing a strong secret in production
We should let the user know if they use a unsafe JWT_SECRET when they are not using production
. jsonwebtoken
uses HS256
as algorithmen, I read an article that it is possible to actually brute force the secret of a HS256 algorithm when using a "bad" secret. Actually one should use a 256 bit secret. which is the equivalent of 32 charcaters, since 1 char is 8 bit.
It would be better to actually throw when using NODE_ENV=production
and not using a strong secret. Also it would be good to let the user know if they are using a "good" secret.
I would recommend something similar to:
// api/services/production.service.js
const productionService = () => {
if (
process.env.NODE_ENV
// we have to choose a strong secret
&& process.env.JWT_SECRET
&& process.env.DB_NAME
&& process.env.DB_USER
&& process.env.DB_USER
&& process.env.DB_PASS
) {
if (process.env.JWT_SECRET.length <= 31) {
throw new Error('Not safe for production: JWT_SECRET should be at least 256 bit, e.g. 32 characters long');
}
return true;
}
throw new Error('Not safe for production: you forgot to set one or more environment variables');
};
module.exports = productionService;
// api/services/auth.service.js
const jwt = require('jsonwebtoken');
const productionService = require('./production.service');
const safeSecret = process.env.JWT_SECRET ? process.env.JWT_SECRET.length >= 32 : true;
const secret = () => {
if (
(
safeSecret
&& process.env.JWT_SECRET
)
||
(
process.env.NODE_ENV === 'production'
&& productionService()
)
) {
return process.env.JWT_SECRET;
}
if (
!safeSecret
&& process.env.JWT_SECRET
) {
console.error('\n\n\nYou are using a JWT_SECRET that would not be safe for production. Keep in mind that your secret should be at least 256 bit, e.g. 32 characters long.\n\n\n')
return process.env.JWT_SECRET;
}
return 'secret';
};
const mySecret = secret();
const authService = () => {
const issue = (payload) => jwt.sign(payload, mySecret, { expiresIn: 10800 });
const verify = (token, cb) => jwt.verify(token, mySecret, {}, cb);
return {
issue,
verify,
};
};
module.exports = authService;