Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always showed Intent to receive required on Xero Webhooks and not x-xero-signature header not matched #240

Closed
MJunaidIqbaal opened this issue Dec 6, 2022 · 9 comments
Assignees

Comments

@MJunaidIqbaal
Copy link

MJunaidIqbaal commented Dec 6, 2022

When a click on Intent to Receive then it always showed me the same like Intent to Received required, not showed 200 OK.

Method for ensuring_security is:

def ensuring_security?
      key = 'XERO_WEBHOOK_KEY'
      payload = request.body.read
      calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest('sha256', key, payload))
      begin
        if calculated_hmac.strip() == request.headers['x-xero-signature']
          true
        else
          false
        end
      rescue JSON::ParserError => e
        false
      end
      
end

The result is alweays false because the calculated_hmac.strip() is not equal to request.headers['x-xero-signature']. I think if the intent can't be 200 OK so if I will updation in Contacts or Invoices the webhook can not be received. So What should I do?

I want to show a result of 200 OK and after this will get a webhook if updation in invoices and contacts.

Screenshot of which is receiving when click on Intent to Receive:
image

You can see in the above screenshot that two values can't be equal; first is from calculated_hmac and second from request.headers['x-xero-signature'].

And on webhook config at Xero site here:
image

So how can I get 200 OK at status and receive invoice status (regarding update any invoice), anyone please reply me ASAP. Thanks!

@MJunaidIqbaal
Copy link
Author

@RettBehrens @pumpkinball please update me on this issue.

@RettBehrens
Copy link
Contributor

Hi @hellojunaydiqbal based on your description it's likely the payload is somehow being altered which then causes failure to verify the signature. @pumpkinball is working on adding a webhooks example to our Ruby sample app. Doing some digging and it looks like I might have found something for you:
https://developer.xero.com/community-forum-archive/discussion/68765406
https://stackoverflow.com/questions/34855049/using-hmac-sha256-in-ruby

@MJunaidIqbaal
Copy link
Author

@RettBehrens thank you so much for your reply. I already read this discussion on xero forums, this is not right fix for my case. Because if I used hexdigest method then the string length is increased and can't be matched. For example, I showed you a screenshot when I used hexdigest method:

Screenshot:
image

You can check it two strings on the above screenshot, the first is from hexdigest and the second is get from request.headers['x-xero-signature']. So the length didn't matched aswell string.

If I'm using Base64.encode64(OpenSSL::HMAC.digest('sha256', key, data)) then the string length is same but didn't matched. According to the Xero webhook docs:

If the payload is hashed using HMACSHA256 with your webhook signing key and base64 encoded, it should match the signature in the header. This is a correctly signed payload. If the signature does not match the hashed payload it is an incorrectly signed payload.

So please provide me with a better solution or any open-source GitHub repo so that I'll get help on webhook.

@MJunaidIqbaal
Copy link
Author

@RettBehrens @pumpkinball respond to me on my issue, please!

@pumpkinball
Copy link
Contributor

Hi @hellojunaydiqbal , I am currently working on this in Ruby on my sample app. So I will keep you posted.
In the meantime what else have you tried please?
Did you also try hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, payload)

@pumpkinball
Copy link
Contributor

Hi @hellojunaydiqbal
I managed to get the signatures to match.
Can you try this format please, and let me know how you get on.
hash = OpenSSL::HMAC.digest('sha256', key, payload)
calc_hmac = Base64.encode64(hash)

@RettBehrens
Copy link
Contributor

Hi @hellojunaydiqbal I've been unable to replicate the issue using the code below

class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token
  
  def webhook
    key = ENV['WEBHOOK_KEY']
    payload = request.body.read
    calculated_hmac = Base64.encode64(OpenSSL::HMAC.digest('sha256', key, payload))
    if calculated_hmac.strip() == request.headers['x-xero-signature']
      render json: {}, status: :ok
    else
      render json: {}, status: :unauthorized
    end
  end
end

Can you please post your app Client ID so we can look into it further?

@pumpkinball
Copy link
Contributor

Hi @hellojunaydiqbal
Just an update on the webhook signature, I was also getting the same issue as you at first.
After chatting with @RettBehrens who had it working, I pulled down Rett's webhooks example branch. The bundle install updated xero-ruby SDK and a few other things.
I also pulled down a new version of Ruby Gems, I did encounter a few issues including one with permissions, and ended up uninstalling rbenv and re-installing it.
Finally I got it working.
For reference here are the versions I'm now working with:-
Rails version 6.0.5
Ruby version ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [arm64-darwin22]
RubyGems version 3.1.6

Let me know how you get on.

@pumpkinball
Copy link
Contributor

Hey @JunaydIqbal
If you're still having an issue, please can you let us have your ClientId and we can take a closer look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants