n8n-io/n8n · error · Error
Certificate authentication requires an RSA private key
Error message
Certificate authentication requires an RSA private key
What it means
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.
Source
Thrown at packages/@n8n/utils/src/client-assertion.ts:70
iat: now,
nbf: now,
exp: now + ASSERTION_TTL_SECONDS,
};
let privateKey: KeyObject;
try {
privateKey = createPrivateKey(formatPemBlock(options.privateKey));
} catch (error) {
throw new Error(
'The Private Key field must contain a PEM private key (-----BEGIN PRIVATE KEY-----).',
{ cause: error },
);
}
// `createSign('RSA-SHA256')` also signs EC/Ed25519 keys, producing a signature
// that contradicts the pinned `alg: RS256` header. Reject non-RSA keys up front.
if (privateKey.asymmetricKeyType !== 'rsa') {
throw new Error('Certificate authentication requires an RSA private key');
}
const signingInput = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(payload))}`;
const signature = createSign('RSA-SHA256').update(signingInput).sign(privateKey);
return `${signingInput}.${base64url(signature)}`;
}
View on GitHub (pinned to 5ac6606e81)
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'.
Example fix
// before
// generated: openssl genpkey -algorithm ED25519 -out private.pem
buildClientAssertion({ ..., privateKey: ed25519Pem }); // throws
// after
// generated: openssl genrsa -out private.pem 2048
buildClientAssertion({ ..., privateKey: rsaPem }); Defensive patterns
Strategy: validation
Validate before calling
import { createPrivateKey } from 'node:crypto';
function assertRsaPrivateKey(key: string): void {
const ko = createPrivateKey(key);
if (ko.asymmetricKeyType !== 'rsa') {
throw new Error(`Expected an RSA private key, got '${ko.asymmetricKeyType}'. Generate with: openssl genrsa -out private.pem 2048`);
}
}
// then call before buildClientAssertion. Type guard
import { createPrivateKey, type KeyObject } from 'node:crypto';
function isRsaPrivateKey(pem: string): boolean {
try {
return createPrivateKey(pem).asymmetricKeyType === 'rsa';
} catch {
return false;
}
} Try / catch
try {
return buildClientAssertion(opts);
} catch (e) {
if (/requires an RSA private key/i.test(e?.message ?? '')) {
throw new ConfigError('Certificate authentication requires an RSA key; regenerate with openssl genrsa.', { cause: e });
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The Certificate field must contain a PEM certificate (-----B
- The Private Key field must contain a PEM private key (-----B
- Unknown algorithm ${algorithm}. Available algorithms are: ${
- Cannot decrease maxIterations when resuming a run. Expected
- Checkpoint for runId ${this.runId} has pending tool calls —
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0e54cbf476dcae53.
Report an issue: GitHub.