we-promise/sure · error · EnableBankingError
invalid_certificate
invalid_certificate
Error message
Invalid private key in certificate: #{e.message} What it means
Raised by Provider::EnableBanking#extract_private_key during initialize when OpenSSL::PKey::RSA.new rejects the client_certificate argument — the string passed as :client_certificate is not a parseable RSA private key PEM. The OpenSSL error message is preserved ('Invalid private key in certificate: ...') and logged. Every subsequent call would fail anyway, so construction aborts immediately.
Source
Thrown at app/models/provider/enable_banking.rb:247
# Otherwise pick the first progressively-shorter window that advances the
# window forward, skipping any window that is not newer than the current
# date_from. Moving strictly forward guarantees progress and termination.
FALLBACK_TRANSACTIONS_DATE_FROM_DAYS
.map { |days| days.days.ago.to_date }
.find { |candidate| current.nil? || candidate > current }
end
def safe_psu_headers(headers)
headers.except("Authorization", :Authorization, "Accept", :Accept, "Content-Type", :"Content-Type")
end
def extract_private_key(certificate_pem)
# Extract private key from PEM certificate
OpenSSL::PKey::RSA.new(certificate_pem)
rescue OpenSSL::PKey::RSAError => e
Rails.logger.error "Enable Banking: Failed to parse private key: #{e.message}"
raise EnableBankingError.new("Invalid private key in certificate: #{e.message}", :invalid_certificate)
end
def generate_jwt
now = Time.current.to_i
header = {
typ: "JWT",
alg: "RS256",
kid: application_id
}
payload = {
iss: "enablebanking.com",
aud: "api.enablebanking.com",
iat: now,
exp: now + 3600 # 1 hour expiry
}
View on GitHub (pinned to e69894adb9)
Solutions
- Read the logged OpenSSL message — 'Could not parse PKey' usually means wrong content, 'Could not find start line' means broken BEGIN/END header
- Re-download the RSA private key PEM from the Enable Banking application settings and pass the full '-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----' block
- Validate locally: openssl rsa -in key.pem -check -noout (add -passin pass:... if the key is encrypted — the client does not support passphrase-encrypted keys)
- Ensure the stored value keeps newlines intact (store as a single-line secret and gsub('\\n', "\n") before use, or store the multiline PEM directly)
Example fix
# before
Provider::EnableBanking.new(application_id: app_id, client_certificate: ENV["EB_CERT"]) # mangled value
# after
key_pem = ENV["EB_PRIVATE_KEY"].to_s.gsub("\\n", "\n")
raise ArgumentError, "EB_PRIVATE_KEY is not an RSA PEM" unless key_pem.include?("BEGIN")
Provider::EnableBanking.new(application_id: app_id, client_certificate: key_pem) Defensive patterns
Strategy: validation
Validate before calling
def valid_enable_banking_rsa_key?(pem)
OpenSSL::PKey.read(pem).is_a?(OpenSSL::PKey::RSA)
rescue OpenSSL::PKey::PKeyError
false
end
# use before building the client:
# raise ArgumentError, "private key is not a valid RSA PEM" unless valid_enable_banking_rsa_key?(ENV["EB_PRIVATE_KEY"].to_s.gsub("\\n", "\n")) Type guard
def eb_invalid_certificate?(error) error.is_a?(Provider::EnableBanking::EnableBankingError) && error.error_type == :invalid_certificate end
Try / catch
begin Provider::EnableBanking.new(application_id: app_id, client_certificate: key_pem) rescue Provider::EnableBanking::EnableBankingError => e raise unless e.error_type == :invalid_certificate raise "Enable Banking credentials misconfigured: paste the full RSA private key PEM (BEGIN/END lines included)" end
Prevention
- Validate the PEM with OpenSSL at settings-save time, not at first sync
- Store the full PEM including BEGIN/END lines; normalize escaped newlines on read
- Never store the portal's public certificate where the private key is expected
- Test with `openssl rsa -in key.pem -check -noout` when copying credentials
When it happens
Trigger: Passing the Enable Banking application's public certificate instead of its private key; a PEM block missing its BEGIN/END lines or with mangled newlines (copied through a channel that strips them); an EC or encrypted key instead of an RSA one; pasting the JSON bundle instead of the PEM.
Common situations: Copy-paste of credentials from the Enable Banking portal into .env or a settings form losing line breaks; storing the 'certificate' field when the portal's private key was downloaded separately; whitespace substitution in YAML/JSON configs.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- {result.error}
- {e.record.errors.full_messages.to_sentence.presence || e.mes
- request_failed
- bad_request
- unauthorized
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/1a00daaf15b44e52.
Report an issue: GitHub.