I have created a REST Endpoint (exposed on force.com site) to allow Webhook integration.

The third party service which POSTS data signs requests including the JSON-stringified body using SHA1 encryption with a key I've defined (and also have stored in Salesforce).

I've not done decryption before and would like to understand how I need to decrypt the payload:


  "content-type": "application/json",
  "x-signature": "2fcff0585cd3af371c0df42ee69e000175e9f414"


  "channel": "server",
  "email": "[email protected]",
  "messageId": "test-message-37q7z9",
  "projectId": "oYOQY8rnYw",
  "replay": true,
  "timestamp": "2018-12-04T16:22:37.195Z",
  "traits": {
    "trait1": 1,
    "trait2": "test",
    "trait3": true
  "type": "identify",
  "userId": "test-user-x1nyrr"

What I have so far in APEX:

global class WebhookRecord {

    global static void doPost() {

        // decrypt data
        String algorithmName = 'SHA1';
        String secret = 'qwerty'; // this is the shared secret
        RestRequest restRequest = RestContext.request;

        // how do I verify the shared secret with the signature?
  • 1
    SHA-1 is not a cryptographic scheme, it is a one-way hash function. Can you share more details about how the remote system generates the X-Signature value?
    – David Reed
    Dec 5, 2018 at 14:39

2 Answers 2


Looks like this webhook is using an HMAC (a form of Message Authentication Code) for validation. The message technically isn't encrypted; it's combined with a shared secret that you establish and then processed through a one-way hash function.

The value you're receiving cannot be decrypted, by design. What you're expected to do is take the payload and calculate your own HMAC, using the shared secret value, and confirm that the value you generated is the same as the X-Signature header you received. That allows you to validate that you and the remote sender both know that secret value, without actually including it in the transmission. Note that it doesn't really authenticate the remote sender as such - it just validates that they know the secret, so the security of the whole solution is proportional to your ability to guard that secret value.

Now I cannot actually test this because I don't know your shared secret (again, by design!) But I think the Apex you'd need to validate this would be along these lines, using the Crypto.generateMac() method:

String secret = 'qwerty'; // this is the shared secret
RestRequest restRequest = RestContext.request;
String signature = restRequest.headers.get('X-Signature');

// If `secret` is a hexadecimal string, I believe you'll need to do `EncodingUtil.convertFromHex()` here, 
// unless the remote system is just treating it as ASCII text.
Blob hmac = Crypto.generateMac('hmacSHA1', Blob.valueOf(restRequest.getBody()), Blob.valueOf(secret));

if (EncodingUtil.convertToHex(hmac) == signature) {
    // Validation passes.

Those whose code not matching singature of HMAC 256 as per 3rd part site. here is bit change on above code

string secret= 'a5db7f9cb87859b703b0e30a5f130d2b'; //Hex Key
String signature = 'acf36fa939dbbb8e05e94814574caaf64ca73cae0701ba435f1ee0768830ca8c';
Blob hmac = Crypto.generateMac('HMACSHA256', blob.valueOf('ABCD'), 

Output can be matched from this website : https://www.freeformatter.com/hmac-generator.html

  • This question is explicitly about SHA-1 hashes. SHA-256 is a different algorithm. Any time you work with hashes or crypto, you have to use the specified algorithm.
    – David Reed
    May 1, 2020 at 12:37
  • thank @DavidReed : I though its just a method parameter. what difference we need to add on code for SHA-256 ?
    – Ankuli
    May 1, 2020 at 13:06
  • my own solution not working when i am using another secret key. Had to use Blob.valueOf(secret). weired
    – Ankuli
    May 1, 2020 at 13:10
  • If you have other issues, please open a new question.
    – David Reed
    May 1, 2020 at 13:12

You must log in to answer this question.

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