In Apex, how do I implement the webhook verification from Ironclad described here?

Their example uses Node.js and basically boils down to this:

const isValid = crypto

  // The data to be verified is a concatenation of eventId, nonce, and the request body

  .verify(publicKey, signature, encoding);

return isValid;

Here is what I'm running in anonymous apex attempting to replicate the above:

String publicKey = //'-----BEGIN PUBLIC KEY-----' + // encoded in PEM format
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' +
'xxxxxxxxxxxxxxxxxxxxxxxx'; // + '-----END PUBLIC KEY-----';
String eventId = 'webhookEventxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
String encoding = 'base64';
String signAlgorithm = 'RSA-SHA256'; // Ironclad returns sha256
String nonce = 'xxxxxxxxxxxxxxxx';
String signature = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=';
String body = '{' +
  '"companyID": "605b9829cdd37d296123f4b4",' +
  '"payload": {' +
    '"event": "workflow_launched",' +
    '"templateID": "6063ac9e01a5542dafa3722b",' +
    '"workflowID": "611fbd699f4a33b41d9f8295"' +
  '},' +
  '"webhookID": "611fb96cb670f852d58db210"' +

Boolean verified = Crypto.verify(
  Blob.valueOf(eventId + nonce + body),


I recognize that there are multiple areas where this test sample could be failing, including the formatting of the JSON body. But is the set up of the Crypto.verify() method correct?

  • 1
    Does this answer your question? Crypto.verify(..) - format of a public key
    – identigral
    Mar 26, 2022 at 15:48
  • @identigral No, it doesn't, but thank you. I did reference that answer when commenting out the BEGIN/END PUBLIC KEY in my publicKey string.
    – Diego
    Mar 27, 2022 at 3:08

1 Answer 1


Two issues:

  1. The Ironclad documentation reads

    The data that will need to be verified is a concatenation of the eventId and nonce properties, and the request body (as a JSON string)...

    listing nonce before body, but their Node example shows nonce as the final item. So really, should be using Blob.valueOf(eventId + body + nonce).

  2. Need to decode the signature EncodingUtil.base64Decode(signature)

Boolean verified = Crypto.verify(
  Blob.valueOf(eventId + body + nonce),

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .