Integrations, ML/AI and Design

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

global class TwitterSF {
    public class myres{
        String response_token;

    global static void getResponse()
        RestRequest restReq = RestContext.request; 
        String crc_token = restReq.params.get('crc_token'); 

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

        Blob data = crypto.generateMac('HmacSHA256',
        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));
    global static void processResponse()
    	//Logic for processing the event. e.g. create case from the tweet
You’ve successfully subscribed to Inteygrate
Welcome back! You’ve successfully signed in.
Great! You’ve successfully signed up.
Your link has expired
Success! Check your email for magic link to sign-in.