Webhook signatures
Get to know how you can view and rotate Webhook Secrets
View a Subscription Webhook Secretβ
Webhooks play a crucial role in integrating Q-Flow events with external systems. To ensure secure communication, Q-Flow utilises webhook secrets and digital signatures to validate the authenticity and integrity of the incoming webhook requests.
To view a Webhook Secret:
- Be sure to be inside an existing Subscription. On the top right handside, press the
cog
icon - Scroll to the
Set a Webhook Endpoint
section. - Press the
Eye
icon. - Once you've viewed the secret, you can now copy the secret to your clipboard.
To rotate a Webhook Secret:
- Be sure to be inside an exsisting Subscription. On the top right handside, press the
cog
icon - Scroll to the
Set a Webhook Endpoint
section. - Press the
rotate
icon. - A modal will appear to reffirm the rotate action. If you're happy to rotate, press the
rotate
button.
When rotating secrets on a webhook, the signed request includes a comma-separated header value containing each active secret. Example: sha256=<signature>,sha256=<signature2>
. The newest key will always appear as the first signature. Incumbent keys will continue to be signed for 7 days, ensuring a smooth transition. After the 7th day, only the new signature will remain active.
Thatβs it! You have successfully viewed and rotated your Webhook Secret key π.
Headers Provided by Q-Flowβ
This guide explains how to validate the signature included in the webhook header, protecting against replay attacks and ensuring compliance with security best practices.
Each webhook sent by Q-Flow contains the following headers:
-
Qflow-Request-Id
: A unique identifier for each webhook event. -
Qflow-TimeStamp
: The Unix epoch time in milliseconds when the webhook request was created. -
Qflow-Signature
: A coma separated header value of the signed request with each secret that is active. Example:sha256=<signature>,sha256=<signature2>
The newest key being the first signature.
The signature is generated using the HMACSHA256 algorithm and consists of:
HMACSHA256(SecretKey, "{RequestId}.{Timestamp}.{RequestBody}")
Where:
SecretKey
is the webhook secret provided when creating a subscription in Q-Flow.
RequestId
and Timestamp
correspond to the values of the Qflow-Request-Id
, Qflow-TimeStamp
, while the RequestBody is a UTF8 string encoding of the request body.
Why Validate Webhook Signatures?β
- Compliance and Security
Validating the Qflow-Signature ensures the webhook request originated from Q-Flow, maintaining compliance with security standards. It safeguards against potential tampering by verifying that the request was not altered during transmission.
- Protection Against Replay Attacks
To protect against replay attacks, you should validate the Qflow-TimeStamp
. If the timestamp falls outside an acceptable window (e.g., more than 5 minutes old), reject the request. The window of time that is acceptable should be based on your own policies. This measure helps ensure that an intercepted request cannot be reused maliciously.
- Additional Considerations
Always compare the computed signature with the received Qflow-Signature
using a time-safe comparison method to avoid timing attacks.
For added security, rotate your webhook secret regularly and update your subscription settings accordingly.
Verify Q-Flow Webhook Signaturesβ
To verify the Qflow-Signature
in a C# application, you can use the following example:
using System;
using System.Security.Cryptography;
using System.Text;
public class WebhookVerifier
{
public static bool VerifySignature(string receivedSignature, string secretKey, string requestId, string eventTimestamp, string payload)
{
// Generate the expected signature
string expectedSignature = BuildExpectedSignature(secretKey, requestId, eventTimestamp, payload);
// Convert the signatures to bytes
byte[] receivedSignatureBytes = Convert.FromBase64String(receivedSignature);
byte[] expectedSignatureBytes = Convert.FromBase64String(expectedSignature);
// Use a time-safe comparison to validate the signatures
return CryptographicOperations.FixedTimeEquals(receivedSignatureBytes, expectedSignatureBytes);
}
private static string BuildExpectedSignature(string secret, string requestId, string eventTimestamp, string payload)
{
// Create the string to sign
string dataToSign = $"{requestId}.{eventTimestamp}.{payload}";
// Decode the secret from base64
byte[] secretKey = Convert.FromBase64String(secret);
// Convert the data to sign to bytes
byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSign);
// Compute the HMACSHA256 hash
using (var hmac = new HMACSHA256(secretKey))
{
byte[] hashBytes = hmac.ComputeHash(dataBytes);
// Convert the hash to a base64 string
return Convert.ToBase64String(hashBytes);
}
}
}
By following these steps, you can ensure that your Q-Flow webhook integrations are secure, preventing tampering and replay attacks while complying with security best practices. Regularly validate your webhook signatures, monitor the timestamp, and use secure comparison methods to safeguard your application.