Examples
BTCPay-Sig HMAC256 verification (C# Code)
This example demonstrates how to verify the BTCPay-Sig
HMAC256 signature included in webhook requests from ElenPAY. Verifying this signature ensures that the webhook payload is authentic and has not been tampered with.
- The
BTCPay-Sig
header contains a SHA256 HMAC of the request body, using your webhook secret as the key. - You must use the exact raw request body to compute the HMAC.
- The webhook secret is provided to you by our ops team during store setup. Store it securely and never expose it publicly.
- If the computed SHA256(HMAC) does not match the value in the
BTCPay-Sig
header, reject the request with a 401 Unauthorized response.
context.Request.EnableBuffering();
if (context.Request.Headers.TryGetValue("BTCPay-Sig", out var signatureHeader))
{
// Leave the body open so the next middleware can read it.
using (var reader = new StreamReader(
context.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 1024 * 100,
leaveOpen: true))
{
var body = await reader.ReadToEndAsync();
// Do some processing with body…
var hmacSecret = Environment.GetEnvironmentVariable("WITHDRAW_WEBHOOK_SECRET");
var bodyBytes = Encoding.UTF8.GetBytes(body);
var secretBytes = Encoding.UTF8.GetBytes(hmacSecret ?? string.Empty);
var expectedHMACbytes = new HMACSHA256(secretBytes).ComputeHash(bodyBytes);
var incomingHMAC = signatureHeader.FirstOrDefault() ?? string.Empty;
var actualHMAC = $"sha256={Encoders.Hex.EncodeData(expectedHMACbytes)}";
// Reset the request body stream position so the next middleware can read it
context.Request.Body.Position = 0;
if (incomingHMAC != actualHMAC)
{
Console.WriteLine($"Invalid HMAC Signature: expected: {incomingHMAC} actual:{actualHMAC}");
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
await context.Response.StartAsync();
}
else
{
// Do work that doesn't write to the Response.
await next(context);
// Do other work that doesn't write to the Response.
}
}
}
else
{
await next(context);
}
Tip: You can use similar logic in other languages (Node.js, Python, Go, etc.) by using their respective HMAC SHA256 libraries and reading the raw request body.
For more details, see the Webhook Security section in the user guide.