Securing webhooks
Callback URL
Fractal ID accepts only secure sites (HTTPS) as callback URLs.
Validating payloads from Fractal ID
When your secret token is set, Fractal ID uses it to create a hash signature with each payload. The hash signature is passed along with each request in the headers as X-Fractal-Signature
.
Fractal ID generates signatures using a hash-based message authentication code (HMAC) with SHA-1.
Your endpoint should verify the signature to make sure it came from Fractal ID. Example implementation in Ruby:
def verify_signature
payload_body = request.body.read
signature = "sha1=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), ENV["WEBHOOK_SECRET_TOKEN"], payload_body)
if Rack::Utils.secure_compare(signature, request.headers["X-Fractal-Signature"])
render json: {}, status: 200
else
render json: { error: "signature_mismatch" }, status: 400
end
end
Your language and server implementations may differ than this code. There are a couple of very important things to point out, however:
Local verification
To aid with your development process, here are some example scripts you can use to validate your assumptions.
require 'openssl'
webhook_secret_token = ARGV[0]
payload_body = ARGV[1]
expected_signature = ARGV[2]
calculated_signature =
OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new("sha1"),
webhook_secret_token,
payload_body,
)
signature_matches = calculated_signature == expected_signature
puts Hash[
webhook_secret_token:,
payload_body:,
expected_signature:,
calculated_signature:,
signature_matches:
].inspect
$ ruby --version
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
$ ruby ver.rb SUP3RS3CR3T my-payload badsig
{:webhook_secret_token=>"SUP3RS3CR3T", :payload_body=>"my-payload", :expected_signature=>"badsig", :calculated_signature=>"6a89633e5f131bfb5f0b5826b33b3bab4bf52068", :signature_matches=>false}
$ ruby ver.rb SUP3RS3CR3T my-payload 6a89633e5f131bfb5f0b5826b33b3bab4bf52068
{:webhook_secret_token=>"SUP3RS3CR3T", :payload_body=>"my-payload", :expected_signature=>"6a89633e5f131bfb5f0b5826b33b3bab4bf52068", :calculated_signature=>"6a89633e5f131bfb5f0b5826b33b3bab4bf52068", :signature_matches=>true}
Last updated
Was this helpful?