logo
Below is a simple example on how to authenticate the webhook payload using a secret key
ruby
#!/usr/bin/env ruby require "webrick" require "openssl" # ------------------------------------------------------------------------------ # Minimal Ruby webhook receiver example. # - Listens on /webhooks # - Reads the raw request body # - Verifies HMAC-SHA256 signatures using a shared secret # ------------------------------------------------------------------------------ PORT = 3000 SECRET_ID = "whsec_<YOUR_SECRET_ID>" SECRET = SECRET_ID.sub(/^whsec_/, "") def secure_compare(a, b) return false if a.nil? || b.nil? return false unless a.bytesize == b.bytesize OpenSSL.fixed_length_secure_compare(a, b) rescue NoMethodError a == b end server = WEBrick::HTTPServer.new(Port: PORT) trap("INT") { server.shutdown } server.mount_proc "/webhooks" do |req, res| begin signature_header = req.header["x-basta-signature"]&.first if signature_header.nil? res.status = 401 res.body = "Missing X-Basta-Signature header" puts "Missing signature header" next end # Expected format: "t=<timestamp>,v1=<signature>" parts = signature_header.split(",") if parts.size != 2 res.status = 401 res.body = "Invalid signature format" puts "Invalid signature format: #{signature_header}" next end timestamp_part, sig_part = parts.map(&:strip) timestamp = timestamp_part.split("=").last received_sig = sig_part.split("=").last if timestamp.nil? || received_sig.nil? || timestamp.empty? || received_sig.empty? res.status = 401 res.body = "Invalid signature components" puts "Invalid signature components: #{signature_header}" next end raw_body = req.body || "" payload_to_sign = "#{timestamp}.#{raw_body}" computed_sig = OpenSSL::HMAC.hexdigest("SHA256", SECRET, payload_to_sign) valid = secure_compare(received_sig, computed_sig) puts "---- Incoming webhook ----" puts "Timestamp: #{timestamp}" puts "Payload bytes: #{raw_body.bytesize}" puts "Computed signature: #{computed_sig}" puts "Received signature: #{received_sig}" puts "Signature valid? #{valid ? 'YES' : 'NO'}" puts "---------------------------" if valid res.status = 200 res.body = "ok" else res.status = 401 res.body = "Invalid signature" end rescue => e puts "Error verifying webhook: #{e.class}: #{e.message}" res.status = 500 res.body = "internal error" end end puts "Listening locally on http://localhost:#{PORT}/webhooks" server.start

Powered by Notaku
Share