Challenge-Response Checks a.k.a CRC in Salesforce

Challenge-Response Checks a.k.a CRC in Salesforce
Photo by Jukan Tateisi / Unsplash

CRC is a mechanism by which the event publisher verifies that the registered subscriber owns the URL that is registered (via webhook) for receiving events. For e.g. Twitter's webhook-based APIs provide the challenge-response checks to confirm the ownership of the web app receiving webhook events.

In this article we will see how can we create one such web app - which is nothing but a Apex REST service, and register it to twitter webhook. This is part of the configuration step required for Twitter Salesforce integration article here.

How CRC works

For a CRC of your Apex REST service, twitter will actually make a GET request to your service with a crc_token parameter. When that request is received, our service needs to build an encrypted response_token based on the crc_token parameter and our twitter app's Consumer Secret. The response_token must be encoded in JSON and returned within three seconds. If successful, a webhook id will be returned.

Recap of CRC Response requirements

  • A base64 encoded HMAC SHA-256 hash created from the crc_token and your app Consumer Secret
  • Valid response_token and JSON format.
  • Latency less than 3 seconds.
  • 200 HTTP response code.

In order to implement this we need a simple Apex REST service made public via Guest profile. The class must have two HTTP request methods

  • GET - triggered when a CRC request is sent by twitter during webhook registration. This will read the crc_token passed as a URL parameter and generate a response as shown below adhering to the response requirements mentioned above. The URL of the service would be of the form https://<SalesforceDomainName>/services/apexrest/{Prefix of your Apex REST Service}?crctoken={random characters set by twitter}.
{
 "responsetoken": "sha256=x0mYd8hz2goCTfcNAaMqENy2BFgJJfJOb4PdvTffpwg=" 
}
  • POST - triggered after a successful webhook registration when any webhook event occurs at twitter end.

Sample Apex REST Service

@RestResource(urlMapping='/{prefix}')
global class TwitterSF {
    public class myres{
        String response_token;
    }

    @HttpGet
    global static void getResponse()
    {
        RestRequest restReq = RestContext.request; 
        String crc_token = restReq.params.get('crc_token'); 
        RestContext.response.addHeader('Content-Type','application/json'); 

        system.debug('crc_token'+crc_token);
        String secretKey = String.valueOf('{Obtained API secret key}');
        String key = 'key';
        String crctoken;

        Blob data = crypto.generateMac('HmacSHA256',
                                       Blob.valueOf(crc_token),Blob.valueOf(secretKey));
        String response = '{'+
            'response_token: sha256=' +EncodingUtil.base64Encode(data)+
            '}';
        myres r = new myres();
        r.response_token = 'sha256='+EncodingUtil.base64Encode(data);
        RestContext.response.responseBody = Blob.valueOf(JSON.serialize(r));
    }
    
    @HttpGet
    global static void processResponse()
    {
    	//Logic for processing the event. e.g. create case from the tweet
    }
}
About the author
Muralidhar Sampathirao

Muralidhar Sampathirao

Sr Technical Consultant @ Salesforce • With thrdz I am designing the building blocks for Enterprise Applications • Articles, opinions and resources expressed/shared are entirely my personal views.

THR(EA)DZ

DZining the building blocks for Enterprise Applications

THR(EA)DZ

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to THR(EA)DZ.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.