Verify signatures

You have a basic webhook endpoint that is ready to accept events from Speed. Make sure your webhook is secure by using a signature to ensure the webhook request was sent from Speed, not from another server.

Speed signs every webhook event sent to your endpoints with a signature in the header. Speed also generates a unique webhook-id and timestamp for each event. If the event needs to be retried (for example, your endpoint replied with a non-2XX status code), Speed will generate a new signature, webhook-id, and timestamp for the new attempt.

To verify signatures, you need to get your endpoint's secret from the Speed Web application's Webhooks settings. Go to Speed Web application’s Webhooks settings, select the endpoint you want to know the secret for, and click the reveal button. You can also get the signing secret (endpoint secret) by calling the API Get Webhook Endpoint By Id. Speed makes a unique secret key for each endpoint and the secret is different for test and live modes.

Let's check out how we can confirm signatures with the solution mentioned here.

Step 1: Extract information from the header

You will find the following information in the header.

INFORMATIONDESCRIPTIONExample value
webhook-signatureEncrypted signature created for this webhook.v1,aacbYYVjTNxNHHEFf4QqyhSkYEkjBKkiUsVQyXb2QUM=
webhook-timestampThe time when the webhook was delivered.1675846768
webhook-idUnique identifier for this webhook message.msg_2LRvZvXpMxN3SDF7taSsmT9RgWHT

Step 2: Prepare the secret string

Get byte[] of the signing secret by removing the prefix _wsec. For example, if the signing secret of an endpoint is wsec_123456, we extract “123456” and then decode using the Base64 decoder. This byte array obtained will be used to verify the signature.

String secret = “wsec_xxxxxxxxxxxxxxxxxxxx”;
byte[] tempSecret = Base64.getDecoder().decode(src:”xxxxxxxxxxxxxxxxxxxxx”);

Step 3: Prepare the signed_payload string

Create the signed_payload string by concatenating these three values, as shown below.

String signPayload = webhook-id + “.” + webhook-timestamp + “.” + requestBody;

Here the request_body can be obtained from the webhook’s incoming payload.

Step 4: Determine the expected signature

The signature will be Base64 encoded using javax.crypto.* library. We have prepared the payload (signPayload) and also the secret (tempSecret). Let’s generate the signature using them, as shown below.

Mac sha512Hmac = Mac.getInstance(HmacSHA256):
SecretKeySpec key Spec = new SecretKeySpec(tempSecret, HmacSHA256);
sha512Hmac.init(keySpec);
Byte[] macData = sha512Hmac.doFinal(signPayload.getBytes(StandardCharsets,UTF_8));
String signature = Base64.getEncoder().encodeToString(macData):

Using the classes and method of javax.crypto.* you can generate the signature.

Step 5: Compare the signatures

Compare the signature (or signatures) in the header to the expected signature. This verification process is optional and is not required for your application to handle Speed webhooks.