{"record":{"id":"0e54cbf476dcae53","repo":"n8n-io/n8n","slug":"certificate-authentication-requires-an-rsa-private","errorCode":null,"errorMessage":"Certificate authentication requires an RSA private key","messagePattern":"Certificate authentication requires an RSA private key","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/utils/src/client-assertion.ts","lineNumber":70,"sourceCode":"\t\tiat: now,\n\t\tnbf: now,\n\t\texp: now + ASSERTION_TTL_SECONDS,\n\t};\n\n\tlet privateKey: KeyObject;\n\ttry {\n\t\tprivateKey = createPrivateKey(formatPemBlock(options.privateKey));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t'The Private Key field must contain a PEM private key (-----BEGIN PRIVATE KEY-----).',\n\t\t\t{ cause: error },\n\t\t);\n\t}\n\n\t// `createSign('RSA-SHA256')` also signs EC/Ed25519 keys, producing a signature\n\t// that contradicts the pinned `alg: RS256` header. Reject non-RSA keys up front.\n\tif (privateKey.asymmetricKeyType !== 'rsa') {\n\t\tthrow new Error('Certificate authentication requires an RSA private key');\n\t}\n\n\tconst signingInput = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(payload))}`;\n\tconst signature = createSign('RSA-SHA256').update(signingInput).sign(privateKey);\n\treturn `${signingInput}.${base64url(signature)}`;\n}\n","sourceCodeStart":52,"sourceCodeEnd":77,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/utils/src/client-assertion.ts#L52-L77","documentation":"Thrown by buildClientAssertion when the parsed private key's asymmetricKeyType is not 'rsa'. The signer pins the JWT alg header to RS256 and uses createSign('RSA-SHA256'); an EC or Ed25519 key would produce a signature that contradicts the declared alg, so non-RSA keys are rejected up front to prevent an invalid token.","triggerScenarios":"Generating an ECDSA P-256 or Ed25519 keypair for OAuth client authentication and supplying the EC/Ed private key. Using a key from a vault/KMS that defaults to EC instead of RSA.","commonSituations":"Modern key-generation defaults (openssl ecparam, ssh-keygen -t ed25519) producing non-RSA keys; security policies mandating EC keys that conflict with this RS256-only signer; misreading the API doc that states RS256-only.","solutions":["Generate an RSA private key: `openssl genrsa -out private.pem 2048` (or 3072/4096).","If you must use an EC key, switch to a signer that supports ES256 and updates the alg header accordingly (this function does not).","Verify the key type at config time: createPrivateKey(pem).asymmetricKeyType === 'rsa'."],"exampleFix":"// before\n// generated: openssl genpkey -algorithm ED25519 -out private.pem\nbuildClientAssertion({ ..., privateKey: ed25519Pem }); // throws\n// after\n// generated: openssl genrsa -out private.pem 2048\nbuildClientAssertion({ ..., privateKey: rsaPem });","handlingStrategy":"validation","validationCode":"import { createPrivateKey } from 'node:crypto';\n\nfunction assertRsaPrivateKey(key: string): void {\n  const ko = createPrivateKey(key);\n  if (ko.asymmetricKeyType !== 'rsa') {\n    throw new Error(`Expected an RSA private key, got '${ko.asymmetricKeyType}'. Generate with: openssl genrsa -out private.pem 2048`);\n  }\n}\n// then call before buildClientAssertion.","typeGuard":"import { createPrivateKey, type KeyObject } from 'node:crypto';\n\nfunction isRsaPrivateKey(pem: string): boolean {\n  try {\n    return createPrivateKey(pem).asymmetricKeyType === 'rsa';\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  return buildClientAssertion(opts);\n} catch (e) {\n  if (/requires an RSA private key/i.test(e?.message ?? '')) {\n    throw new ConfigError('Certificate authentication requires an RSA key; regenerate with openssl genrsa.', { cause: e });\n  }\n  throw e;\n}","preventionTips":["Generate OAuth client keys with RSA: `openssl genrsa -out private.pem 2048`.","Check asymmetricKeyType at config load to fail fast with a clear message.","Keep key-generation instructions explicit about RSA where this signer is used."],"tags":["n8n-utils","jwt","oauth","crypto","rsa","validation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}