The Exact Error
Error: secretOrPrivateKey must have a value
JsonWebTokenError: invalid key size
Error: The secret length must be >= 32 bytes for HS256
io.jsonwebtoken.security.WeakKeyException: The signing key's size is 120 bits which is not secure enough for the HS256 algorithm
Quick summary: The JWT signing secret is too short for the algorithm being used. HS256 needs at least 32 bytes; using
'secret'(6 bytes) violates this requirement.
Why This Error Happens
HMAC-based JWT algorithms have minimum key size requirements defined in RFC 7518:
| Algorithm | Minimum key length |
|---|---|
| HS256 | 256 bits (32 bytes) |
| HS384 | 384 bits (48 bytes) |
| HS512 | 512 bits (64 bytes) |
Common causes:
1. Short development secret ā using 'secret', 'mysecret', or any string under 32 bytes
2. Environment variable not set ā process.env.JWT_SECRET is undefined
3. Wrong algorithm for key type ā using RSA public key with HS256
Step-by-Step Diagnosis
Step 1 ā Check the secret length
const secret = process.env.JWT_SECRET;
console.log('Secret length (bytes):', Buffer.byteLength(secret, 'utf8'));
// Must be >= 32 for HS256
Step 2 ā Check for undefined
if (!process.env.JWT_SECRET) {
throw new Error('JWT_SECRET environment variable is not set');
}
Step 3 ā Check algorithm compatibility
// RS256 requires RSA private key, not a string secret
// HS256 requires a string/buffer secret
const algorithm = 'HS256'; // or RS256, ES256
Solutions
Solution 1 ā Generate a proper secret
# Node.js ā generate 64 random bytes as hex (128 hex chars = 512 bits)
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
# Or base64
node -e "console.log(require('crypto').randomBytes(64).toString('base64'))"
Add to .env:
JWT_SECRET=your-generated-64-byte-hex-string-here
Solution 2 ā Validate the secret at startup
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET) {
throw new Error('JWT_SECRET is required');
}
if (Buffer.byteLength(JWT_SECRET, 'utf8') < 32) {
throw new Error('JWT_SECRET must be at least 32 bytes for HS256');
}
Solution 3 ā Use RS256 with proper key pair (recommended for production)
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
const token = jwt.sign({ userId: 1 }, privateKey, { algorithm: 'RS256' });
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
Real-World Examples
Express JWT middleware:
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET;
if (Buffer.byteLength(secret, 'utf8') < 32) {
throw new Error('JWT_SECRET too short ā minimum 32 bytes for HS256');
}
export function signToken(payload) {
return jwt.sign(payload, secret, { algorithm: 'HS256', expiresIn: '1h' });
}
export function verifyToken(token) {
return jwt.verify(token, secret, { algorithms: ['HS256'] });
}
Quick Reference ā Key Size Requirements
| Algorithm | Type | Min Key Size | Use Case |
|---|---|---|---|
| HS256 | Symmetric | 32 bytes | Internal services |
| HS384 | Symmetric | 48 bytes | Internal services |
| HS512 | Symmetric | 64 bytes | Internal services |
| RS256 | Asymmetric | 2048-bit RSA | Public APIs |
| ES256 | Asymmetric | P-256 curve | Public APIs |
Prevent This Error in the Future
1. Generate secrets programmatically ā never type a JWT secret by hand.
2. Validate secret length at app startup ā fail fast rather than discovering the error at runtime.
3. Use RS256 for APIs that will have multiple consumers or public key distribution.
Use ToolNinja to Debug Faster
The JWT Generator lets you create and inspect JWTs interactively ā useful for verifying token structure and testing signing with different algorithms.