{"record":{"id":"83be1cd27b4f6487","repo":"auth0/node-jsonwebtoken","slug":"alg-parameter-algorithm-requires-curve-a","errorCode":null,"errorMessage":"\"alg\" parameter \"${algorithm}\" requires curve \"${allowedCurve}\".","messagePattern":"\"alg\" parameter \"(.+?)\" requires curve \"(.+?)\"\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/validateAsymmetricKey.js","lineNumber":46,"sourceCode":"  if (!allowedAlgorithms.includes(algorithm)) {\n    throw new Error(`\"alg\" parameter for \"${keyType}\" key type must be one of: ${allowedAlgorithms.join(', ')}.`)\n  }\n\n  /*\n   * Ignore the next block from test coverage because it gets executed\n   * conditionally depending on the Node version. Not ignoring it would\n   * prevent us from reaching the target % of coverage for versions of\n   * Node under 15.7.0.\n   */\n  /* istanbul ignore next */\n  if (ASYMMETRIC_KEY_DETAILS_SUPPORTED) {\n    switch (keyType) {\n    case 'ec':\n      const keyCurve = key.asymmetricKeyDetails.namedCurve;\n      const allowedCurve = allowedCurves[algorithm];\n\n      if (keyCurve !== allowedCurve) {\n        throw new Error(`\"alg\" parameter \"${algorithm}\" requires curve \"${allowedCurve}\".`);\n      }\n      break;\n\n    case 'rsa-pss':\n      if (RSA_PSS_KEY_DETAILS_SUPPORTED) {\n        const length = parseInt(algorithm.slice(-3), 10);\n        const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails;\n\n        if (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm) {\n          throw new Error(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of \"alg\" ${algorithm}.`);\n        }\n\n        if (saltLength !== undefined && saltLength > length >> 3) {\n          throw new Error(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of \"alg\" ${algorithm}.`)\n        }\n      }\n      break;\n    }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L28-L64","documentation":"For EC keys, each ES* algorithm mandates a specific NIST curve (ES256 -> P-256, ES384 -> P-384, ES512 -> P-521). jsonwebtoken compares the key's asymmetricKeyDetails.namedCurve against the required curve and throws when they differ, since Node's crypto would otherwise produce a mismatched/invalid signature length.","triggerScenarios":"jwt.sign(payload, ecKey, { algorithm: 'ES256' }) where the EC key was generated on the P-384 or secp256k1 curve instead of prime256v1 (P-256).","commonSituations":"Generating EC keys without specifying namedCurve (some tooling defaults to P-384 or secp256k1); keys exported from cloud KMS or OpenSSL with a curve that doesn't match the chosen algorithm; switching algorithms from ES256 to ES384 without regenerating the key.","solutions":["Regenerate the key with the matching curve: crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' }) for ES256 ('P-384' for ES384, 'P-521' for ES512)","Or change the algorithm to match the existing curve (P-384 key -> ES384)","Check the curve with key.asymmetricKeyDetails.namedCurve before signing"],"exampleFix":"// before\nconst { privateKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' });\njwt.sign(payload, privateKey, { algorithm: 'ES256' });\n// after\nconst { privateKey } = crypto.generateKeyPairSync('ec', { namedCurve: 'P-256' });\njwt.sign(payload, privateKey, { algorithm: 'ES256' });","handlingStrategy":"validation","validationCode":"const curveForAlg = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' };\nfunction ecCurveMatches(alg, key) {\n  if (!/^ES/.test(alg)) return true;\n  return key.asymmetricKeyDetails?.namedCurve === curveForAlg[alg];\n}\nif (!ecCurveMatches(alg, key)) throw new Error('Curve ' + key.asymmetricKeyDetails.namedCurve + ' does not match ' + alg);","typeGuard":"function isEsAlgWithMatchingCurve(alg, key) {\n  const required = { ES256: 'P-256', ES384: 'P-384', ES512: 'P-521' }[alg];\n  return !required || key.asymmetricKeyDetails?.namedCurve === required;\n}","tryCatchPattern":"try {\n  return jwt.sign(payload, ecKey, { algorithm: alg });\n} catch (err) {\n  if (/requires curve/.test(err.message)) {\n    const algByCurve = { 'P-256': 'ES256', 'P-384': 'ES384', 'P-521': 'ES512' };\n    return jwt.sign(payload, ecKey, { algorithm: algByCurve[ecKey.asymmetricKeyDetails.namedCurve] });\n  }\n  throw err;\n}","preventionTips":["Always specify namedCurve explicitly when generating EC keys","Generate the curve from the algorithm, not the other way around","Log namedCurve when importing keys from KMS/HSM or OpenSSL","Add a startup key-integrity check that pairs curve to algorithm"],"tags":["jwt","ec-curve","algorithm-mismatch"],"backgroundTag":"jwt-key-curve-mismatch","analyzedSha":"b924272f29192e12926b5414546f7c5bfcc9579d","analyzedAt":"2026-09-02T21:29:06.876Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}