Skip to main content

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:

View and Copy Secret

  1. Be sure to be inside an existing Subscription. On the top right handside, press the cog icon
  2. Scroll to the Set a Webhook Endpoint section.
  3. Press the Eye icon.
  4. Once you've viewed the secret, you can now copy the secret to your clipboard.

To rotate a Webhook Secret:

Rotate Secret

  1. Be sure to be inside an exsisting Subscription. On the top right handside, press the cog icon
  2. Scroll to the Set a Webhook Endpoint section.
  3. Press the rotate icon.
  4. 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:

  1. Qflow-Request-Id: A unique identifier for each webhook event.

  2. Qflow-TimeStamp: The Unix epoch time in milliseconds when the webhook request was created.

  3. 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?​

  1. 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.

  1. 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.

  1. 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.