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.
INFORMATION | DESCRIPTION | Example value |
---|---|---|
webhook-signature | Encrypted signature created for this webhook. | v1,aacbYYVjTNxNHHEFf4QqyhSkYEkjBKkiUsVQyXb2QUM= |
webhook-timestamp | The time when the webhook was delivered. | 1675846768 |
webhook-id | Unique 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.