Webhook Notification

How secret code works.

Secret code is a secret value shared between the webhook sender and receiver. It is used to create an x-signature - a value calculated by the webhooks caller on the secret code given by the receiver and the request JSON data. 

Secret code is included in the webhook registration that was sent to the server during the registration.
Please read more about webhook registration here.

When sending a webhook notification, Litium webhook sender uses secret code to create a SHA256 hasher, then the whole body will be serialized and then hashed using that hasher. This value will be set to the x-signature key in the header before sending the webhook notification to the receiver. 

To verify that webhook notification is in fact called by Litium, the webhooks controller could implement the following methods to validate the received signature before processing the answer:

/// <summary>
        /// Verifies that the signature header matches that of the actual body.
        /// </summary>
        protected virtual async Task VerifySignature(string id, HttpRequestMessage request)
        {
            var secretKey = await GetReceiverConfig(request, Name, id, SecretMinLength, SecretMaxLength);

            // Get the expected hash from the signature header
            var header = GetRequestHeader(request, SignatureHeaderName);
            var values = header.SplitAndTrim('=');
            if (values.Length != 2 || !string.Equals(values[0], SignatureHeaderKey, StringComparison.OrdinalIgnoreCase))
            {
                var message = string.Format(CultureInfo.CurrentCulture, CustomReceiverResources.Receiver_BadHeaderValue, SignatureHeaderName, SignatureHeaderKey, "<value>");
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message);
                var invalidHeader = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidHeader);
            }

            byte[] expectedHash;
            try
            {
                expectedHash = EncodingUtilities.FromHex(values[1]);
            }
            catch (Exception ex)
            {
                var message = string.Format(CultureInfo.CurrentCulture, CustomReceiverResources.Receiver_BadHeaderEncoding, SignatureHeaderName);
                request.GetConfiguration().DependencyResolver.GetLogger().Error(message, ex);
                var invalidEncoding = request.CreateErrorResponse(HttpStatusCode.BadRequest, message);
                throw new HttpResponseException(invalidEncoding);
            }

            // Compute the actual hash of the request body
            byte[] actualHash;
            var secret = Encoding.UTF8.GetBytes(secretKey);
            using (var hasher = new HMACSHA256(secret))
            {
                var data = await request.Content.ReadAsByteArrayAsync();
                actualHash = hasher.ComputeHash(data);
            }

            // Now verify that the actual hash matches the expected hash.
            if (!WebHookReceiver.SecretEqual(expectedHash, actualHash))
            {
                var badSignature = CreateBadSignatureResponse(request, SignatureHeaderName);
                throw new HttpResponseException(badSignature);
            }
        }

In case of a passcode change, the webhook must be unregistered and registered with the new passcode.