{"record":{"id":"2e4133e7f1229290","repo":"n8n-io/n8n","slug":"the-private-key-field-must-contain-a-pem-private-k","errorCode":null,"errorMessage":"The Private Key field must contain a PEM private key (-----BEGIN PRIVATE KEY-----).","messagePattern":"The Private Key field must contain a PEM private key \\(-----BEGIN PRIVATE KEY-----\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/utils/src/client-assertion.ts","lineNumber":61,"sourceCode":"\nexport function buildClientAssertion(options: BuildClientAssertionOptions): string {\n\tconst now = Math.floor(Date.now() / 1000);\n\tconst header = { alg: 'RS256', typ: 'JWT', x5t: certificateThumbprint(options.certificate) };\n\tconst payload = {\n\t\taud: options.accessTokenUri,\n\t\tiss: options.clientId,\n\t\tsub: options.clientId,\n\t\tjti: randomUUID(),\n\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":43,"sourceCodeEnd":77,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/utils/src/client-assertion.ts#L43-L77","documentation":"Thrown by buildClientAssertion when createPrivateKey(formatPemBlock(privateKey)) raises. The wrapper message states the Private Key field must be a PEM private key; the original crypto error is attached as `cause`. The key is used to RS256-sign the client-assertion JWT.","triggerScenarios":"Passing an empty key, a certificate PEM instead of a private key PEM, an encrypted PKCS#8 key without a passphrase, a malformed/truncated PEM, or a key in a format Node cannot parse (e.g. OpenSSH new-format).","commonSituations":"Swapping the certificate and private key fields in config; copy-paste losing the END marker; exporting a public key by mistake; encrypted keys where the runtime has no passphrase; line-ending corruption (CRLF) breaking PEM parsing.","solutions":["Confirm the PEM starts with '-----BEGIN PRIVATE KEY-----' (or 'BEGIN RSA PRIVATE KEY') and has the matching END.","Make sure you pasted the private key, not the certificate.","If the key is encrypted, decrypt it or supply the passphrase and use the appropriate loader.","Inspect err.cause for the specific crypto error (e.g. unsupported key type)."],"exampleFix":"// before\nbuildClientAssertion({ ..., privateKey: certPem }); // swapped\n// after\nbuildClientAssertion({ ..., privateKey: privateKeyPem }); // -----BEGIN PRIVATE KEY-----...","handlingStrategy":"validation","validationCode":"import { createPrivateKey } from 'node:crypto';\n\nfunction assertValidPrivateKeyPem(key: string): void {\n  if (!key || !/-----BEGIN (RSA |EC |ENCRYPTED |)PRIVATE KEY-----/.test(key)) {\n    throw new Error('privateKey must be a PEM string bounded by BEGIN/END PRIVATE KEY markers');\n  }\n  createPrivateKey(key); // throws on malformed input\n}","typeGuard":"function looksLikePemPrivateKey(v: unknown): v is string {\n  return typeof v === 'string'\n    && /-----BEGIN (RSA |EC |ENCRYPTED |OPENSSH |)PRIVATE KEY-----[\\s\\S]*-----END/.test(v);\n}","tryCatchPattern":"try {\n  return buildClientAssertion(opts);\n} catch (e) {\n  if (/must contain a PEM private key/i.test(e?.message ?? '')) {\n    throw new ConfigError('private key field is not a valid PEM private key', { cause: e });\n  }\n  throw e;\n}","preventionTips":["Validate the PEM markers before calling buildClientAssertion.","Do not confuse the certificate and private key fields in config.","For encrypted keys, decrypt or supply a passphrase via the appropriate loader."],"tags":["n8n-utils","jwt","oauth","crypto","private-key","validation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}