gchq/CyberChef · error · OperationError

Error: Have you entered the key correctly? The key should be

Error message

Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.

${err}

What it means

Thrown by JWT Sign when jsonwebtoken's sign() rejects. The hint in the message points at the two dominant causes: a key that does not match the chosen algorithm, or a header argument that is not valid JSON. sign() throws for key/algorithm mismatch, malformed PEM, invalid header JSON, or unsupported algorithm.

Source

Thrown at src/core/operations/JWTSign.mjs:62

            }
        ];
    }

    /**
     * @param {JSON} input
     * @param {Object[]} args
     * @returns {string}
     */
    run(input, args) {
        const [key, algorithm, header] = args;

        try {
            return jwt.sign(input, key, {
                algorithm: algorithm === "None" ? "none" : algorithm,
                header: JSON.parse(header || "{}")
            });
        } catch (err) {
            throw new OperationError(`Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.

${err}`);
        }
    }

}

export default JWTSign;

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Match the key to the algorithm: shared secret for HMAC, PEM private key for RSA/ECDSA.
  2. Ensure the header argument is strict JSON (double quotes, parseable by JSON.parse).
  3. For RSA/ECDSA, supply a valid unencrypted PEM private key.
  4. Verify the algorithm name is one jsonwebtoken supports.

Example fix

// before: HMAC algorithm but a PEM key
chef.JWTSign(payload, { key: pemPrivateKey, algorithm: 'HS256', header: '{}' });
// after: algorithm matches the key
chef.JWTSign(payload, { key: 'my-secret', algorithm: 'HS256', header: '{}' });
Defensive patterns

Strategy: validation

Validate before calling

function validateJwtSignArgs(key, algorithm, header) {
  if (algorithm && algorithm !== 'None')
    JSON.parse(header || '{}'); // header must be JSON
  const isPem = /-----BEGIN/.test(String(key));
  if (/^HS/.test(algorithm) && isPem) throw new Error('HMAC needs a shared secret, not a PEM');
  if (/^(RS|ES|PS)/.test(algorithm) && !isPem) throw new Error('RSA/ECDSA needs a PEM private key');
}

Type guard

function keyMatchesAlgorithm(key, algorithm) {
  const isPem = /-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(String(key));
  return /^HS|^none$/i.test(algorithm) ? !isPem : isPem;
}

Try / catch

try {
  return chef.JWTSign(input, { key, algorithm, header });
} catch (e) {
  if (/entered the key correctly/.test(e.message))
    throw new Error('Algorithm/key mismatch or bad header JSON');
  throw e;
}

Prevention

When it happens

Trigger: Selecting an HMAC algorithm (HS256) but supplying a PEM private key; selecting RSA/ECDSA but supplying a plain-text secret; header argument that is not parseable JSON (e.g. '{alg: x}'); a malformed or encrypted PEM; an algorithm string the library does not recognise.

Common situations: Copying a key from the wrong format. Forgetting that 'None' maps to 'none'. Passing a header with single quotes or trailing commas. Using an ECDSA key with an RSA algorithm selection.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/9c78b2d01fd5171d. Report an issue: GitHub.