I’m working on a Ruby on Rails application and trying to implement webhooks. So far, all test webhooks pass signature verification. However, the webhooks I’m listening to (refund.updated) that get triggered by API interactions fail to verify the signature.
Application ID: sandbox-sq0idb-ijUBhp4f2JVacvzFnKliRg
Looking at the logs I do see retry’s for the
refund.updated event. Is the application responding with a
200 within 10 seconds of delivery?
Hey @Bryan-Square, I might not have been clear enough in my first post.
We can’t return 200, the signature is not verifiable from the webhook. All test events verify just fine but without changing any code, the real ones do not get verified correctly.
You should be able to respond with a
200 prior to verifying the signature.
Ok, but my question on the forum is because I can’t verify the signature and I’m looking for help there. If I respond with
200s when the signature is not verified, what will that do for me?
Hey @Bryan-Square forgot to ping you on this, not sure if you saw it.
In your logs I was seeing retry’s which means that we think you didn’t receive the webhook. We want to make sure you are correctly receiving them to next verify and validate the webhook.
@Bryan-Square the request always responds with
2XX now. Can you help me debug why a test event signature verifies correctly but a real event from the sandbox does not?
This is what the verification code looks like which works for test events sent through the dashboard:
# Validates HMAC-SHA1 signatures included in webhook notifications to ensure notifications came from Square
def valid_square_signature?(body, signature)
square_webhook_signature_key = ENV['SQUARE_WEBHOOK_SIGNATURE_KEY']
logger.warn "HandleSquareWebhook: Cannot verify webhook, missing signature key. Aborting."
# Combine your webhook notification URL and the JSON body of the incoming request into a single string
string_to_sign = WEBHOOK_URL + body.gsub(/\s+/, "")
# Generate the HMAC-SHA1 signature of the string, signed with your webhook signature key
string_signature = Base64.strict_encode64(OpenSSL::HMAC.digest('sha1', square_webhook_signature_key, string_to_sign))
# Hash the signatures a second time (to protect against timing attacks)
# and compare them
Digest::SHA1.base64digest(string_signature) == Digest::SHA1.base64digest(signature)
A psuedo-algorithm to verify the signature of a webhook delivery is described below.
- Step 1: Extract the signature(s) from the request.
- Step 2: Compute the expected valid signature.
- Step 3: Compare the signatures.
That is an incredibly unhelpful response. I’ve explained that the signature verification works with the test events sent from Square. I’ve also provided the actual code used to verify.
@Bryan-Square just thought I’d check with you one more time as I have made adjustments based on your previous message.
With the changes it’s still validating just the test webhooks? Also recently we discovered an issue with the keys. The team recommends that apps use the
raw bytes from the request rather than converting the object representation in your language back to bytes for signature validation.