Webhook security

Once you have your basic endpoint and response working, augment it with an additional security step to know that the data payload is secure.

Alter your code to add a signature verification step before responding to the event with HTTP 200 or HTTP 201. The event header includes a timestamp and hash that you can use to

  1. verify that the event timestamp is less than a few minutes old
  2. compute the same signature using your unique Fullscript-signature secret key
fyi

The Fullscript server will try to send event notices multiple times. So we recommend against adding other complex tasks before returning the 200 or 201 response. If you take too long to respond, your app may receive a second notification for the same event.

Checking the Fullscript-Signature header

Fullscript sends a header in the webhook request that can be used in conjunction with your Webhook Secret Key to verify the payload. Here is an example of the header:

Fullscript-Signature: t=1591826856,v1=0c262932b0ac6b4952e2fe24fdf419313984a66f6f442e0b8ec4cb87f2a107ad

This represents the format: t=<timestamp>,v1=<signature>

The signature is generated using a hash-based message authentication code (HMAC) with SHA-256. This hash is generated using 3 things:

  • A UTC timestamp

  • The request_body (The POST message's JSON payload string)

  • Your Webhook Secret Key

    The timestamp and request_body are combined to create the payload provided to the hash function. The Webhook Secret Key is used as the key. The same hash can be computed and compared to the signature to verify the request.

To recompute and compare the hash, follow these steps

  • Extract the timestamp and signature from the header.

  • Create the payload by combining the timestamp and request_body with a single .

    Example: payload = '1591826856.{"event":{...<more_json>}}'

  • Compute an HMAC with the SHA256 hash function. Use the Webhook Secret Key as the key. Use the payload string as the message.

  • Compare the result with the signature.

  • If they match, the request payload is legitimate.

fyi

The timestamp is generated directly before we send the payload. It is included in the hash payload in order to help prevent replay attacks. We recommend using this to verify the age of a request with a reasonable tolerance. 5 minutes is usually a good default.