Notify Service: Webhooks

When making a request to Notify services, you need webhooks to get the actual results. In order to add your webhook endpoints, you need to add them in your Notify Settings page. You can add as many webhook endpoints as you want, just make sure that you have a different name for each webhook endpoint since it is the name of the webhook endpoint that you will pass along in your request so that the service knows where to post the results. To know more about the data passed through webhooks by each service, visit the documentation on the different service api pages.

Webhook Flow

After you make a request to a specific service, the service will process the request and when it finishes it, whether it encountered an error or not, it will post back the results on the webhook endpoint you specified. Once you receive the request, you need to respond as soon as possible and avoid doing some long processing task before responding. If you respond with a status code other than a 200, the service will attempt to send the results again at certain intervals to be discussed later in detail.

Webhook Security: Verifying source of request and validity of data

In order to verify that the request to your endpoint is coming from the service, a webhook key signature key is attached to the header. A webhook key signature is a cryptographic representation of data used to verify the authenticity and integrity of incoming webhook requests. You will find this signature under cliqet-signature in the header. Once you retrieve this, you can generate a webhook signature based on the raw body of the request and your api key. If the signature in the header matches with the one you have generated based on the body of the request and your api key, this means that the request is valid and that the data has not been tampered. The signature is generated using hash-based message authentication code (HMAC) with SHA-256. Below are sample codes in different languages to verify the signature.

Sample Code:

# Using Flask
import hashlib
import hmac
import base64
from flask import Flask, request

app = Flask(__name__)
api_token = '<YOUR API TOKEN>'

def verify_signature(request_body, hmac_header, api_token):
    data_bytes = request_body.encode('utf-8')
    digest = hmac.new(api_token.encode('utf-8'), data_bytes, digestmod=hashlib.sha256).digest()
    computed_hmac = base64.b64encode(digest).decode('utf-8')
    return hmac.compare_digest(computed_hmac.encode('utf-8'), hmac_header.encode('utf-8'))

@app.route('/webhook', methods=['POST'])
def webhook():
    request_body = request.get_data(as_text=True)
    hmac_header = request.headers.get('cliqet-signature')

    is_valid = verify_signature(request_body, hmac_header, api_token)

    if is_valid:
        # Signature is valid
        ...

if __name__ == '__main__':
    app.run(port=3000)

Webhook Security: Prevent Replay Attacks

A replay attack is a form of cyber attack where an attacker intercepts and maliciously retransmits previously captured data or communication, aiming to deceive a system into accepting and processing it as legitimate, potentially leading to unauthorized actions or compromising sensitive information. It is possible that someone intercepts your valid request and send them again. In order to prevent this, the webhook data includes the time that it was completed and sent to your endpoint. You can determine an appropriate timeframe where you can consider the request as invalid already and reject it.

Handling Repeated Request

When you sent the initial request to the service, you supplied a source_id which is the unique identifier for your request. This source_id is passed as well in the webhook data. You can use this to identify whether the request has been received already and has been processed on your end.

Retry Attempts

When the service does not receive a response from your endpoint, it will attempt to post it again at different intervals. The service will attempt 5 more requests after the initial failed request. After that, it will terminate the attempt to request. Take note that no data is stored regarding the results. The interval of the attempts are as follows:

  • 5 seconds
  • 10 seconds
  • 20 seconds
  • 40 seconds
  • 60 seconds

Protecting your API key

Make sure that your API key is never exposed. If you feel that it may have been compromised, you can always generate a new one. This will invalidate the previous API key