Signature Validation
When you create a webhook in the bitvora console, you will be given a secret. This secret is used to sign the webhook payload. You can use this secret to validate the webhook signature.
Example Signature Validation
Node.js
validateWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const hmac = createHmac("sha256", secret);
hmac.update(payload);
const hash = hmac.digest("hex");
return hash === signature;
}
// inside a controller
handleBitvoraWebhook(@Body() body: any, @Req() req: any): string {
let signature = req.headers['bitvora-signature'];
let bitvora = new BitvoraClient('api_key', 'signet');
let stringBody = JSON.stringify(body);
console.log(stringBody);
if (
validateWebhookSignature(
stringBody,
signature,
'8a83fed4f7c7fed7e57f7c2fe6fa5e9dfd38dfab56b3498dc76e8d43241daa5c', // example secret
)
) {
console.log('Invalid signature');
} else {
console.log('Valid signature');
}
console.log('Received webhook', body);
console.log('Signature', signature);
return this.appService.handleBitvoraWebhook(body);
}
Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"io/ioutil"
)
func validateWebhookSignature(payload, signature, secret string) bool {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(payload))
expectedSignature := hex.EncodeToString(h.Sum(nil))
return expectedSignature == signature
}
func handleBitvoraWebhook(w http.ResponseWriter, r *http.Request) {
secret := "8a83fed4f7c7fed7e57f7c2fe6fa5e9dfd38dfab56b3498dc76e8d43241daa5c" // example secret
signature := r.Header.Get("bitvora-signature")
bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading request body", http.StatusBadRequest)
return
}
payload := string(bodyBytes)
if validateWebhookSignature(payload, signature, secret) {
fmt.Println("Valid signature")
// Process webhook
w.WriteHeader(http.StatusOK)
w.Write([]byte("Webhook received"))
} else {
fmt.Println("Invalid signature")
http.Error(w, "Invalid signature", http.StatusUnauthorized)
}
}
func main() {
http.HandleFunc("/webhook", handleBitvoraWebhook)
http.ListenAndServe(":8080", nil)
}
PHP
<?php
function validateWebhookSignature($payload, $signature, $secret) {
$hash = hash_hmac('sha256', $payload, $secret);
return hash_equals($hash, $signature);
}
function handleBitvoraWebhook() {
$secret = "8a83fed4f7c7fed7e57f7c2fe6fa5e9dfd38dfab56b3498dc76e8d43241daa5c"; // example secret
$signature = $_SERVER['HTTP_BITVORA_SIGNATURE'];
$payload = file_get_contents('php://input');
if (validateWebhookSignature($payload, $signature, $secret)) {
error_log("Valid signature");
// Process webhook
http_response_code(200);
echo "Webhook received";
} else {
error_log("Invalid signature");
http_response_code(401);
echo "Invalid signature";
}
}
handleBitvoraWebhook();
?>
Python
import hmac
import hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
def validate_webhook_signature(payload, signature, secret):
hash = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(hash, signature)
@app.route('/webhook', methods=['POST'])
def handle_bitvora_webhook():
secret = "8a83fed4f7c7fed7e57f7c2fe6fa5e9dfd38dfab56b3498dc76e8d43241daa5c" # example secret
signature = request.headers.get('bitvora-signature')
payload = request.get_data(as_text=True)
if validate_webhook_signature(payload, signature, secret):
print("Valid signature")
# Process webhook
return jsonify({"message": "Webhook received"}), 200
else:
print("Invalid signature")
return jsonify({"message": "Invalid signature"}), 401
if __name__ == '__main__':
app.run(port=8080)