Why should I validate the signature?
There are many reasons, but the main ones are security and data integrity. By validating our signature, you can ensure that the content of the webhook actually comes from Absencelist and that it has not been altered since it was sent by us.
What is a signature?
Every time a webhook is sent from Absencelist, we sign it with an HMAC-SHA256 hash, which is generated based on the content, the time it was sent, the message ID, and the secret key you provided for the webhook. This hash is then Base64-encoded and added to the header "x-webhook-signature".
The hash is generated from the following three elements:
- The content of the webhook (referred to as "message" below)
- The timestamp when the message was sent (found in the header "x-webhook-original-sent")
- The webhook's message ID ("x-webhook-original-messageid")
The HMAC hashing uses the webhook's secret key as the secret.
How do I validate a signature?
To validate a webhook, you need to generate a signature on your side and compare it with the webhook's signature. You do this through the following steps:
- Create a string that includes the message, timestamp, and message ID in the format "message||timestamp||messageid"
- Generate an HMAC hash of the string’s bytes using the secret key as the secret
- Convert the hash into a Base64 string
- Compare the string with our signature
If the signatures match, everything is correct, and you can proceed with processing the webhook.
Example
Here is an example of how to calculate a signature in C#.
var secret = "examplesecret"; var message = @"This is an example"; var messageSent = DateTimeOffset.Parse("2025-01-01 00:00:00.0000000 +00:00"); var messageId = Guid.Parse("f8967ad8-42ab-4872-b882-6ca7eb775218"); var hmac = new HMACSHA256( Encoding.UTF8.GetBytes(secret) ); var hash = hmac.ComputeHash( Encoding.UTF8.GetBytes( $"{message}||{messageSent}||{messageId}" ) ); var hashString = Convert.ToBase64String(hash); //hashString: Ua1Kmw2K9k6RkEKU7kUI8ArLMbWXL1D0i++bBaB/ShM=
Test the validation
Given these parameters:
- Secret key = "examplesecret"
- Message/content = "This is an example"
- Timestamp = "2025-01-01 00:00:00.0000000 +00:00"
- MessageID = "f8967ad8-42ab-4872-b882-6ca7eb77521"
You should get the Base64-encoded string "Ua1Kmw2K9k6RkEKU7kUI8ArLMbWXL1D0i++bBaB/ShM=" as a result. If you got this, everything works, and you can use your function to validate our webhooks.