OAuth 1.0 to Xero accounting private application

Tags: #<Tag:0x00007f31d2d29028> #<Tag:0x00007f31d2d28dd0>

I’m trying to connect to Xero via their private application system.

Full disclosure here this is my first time working certificates. I’ve copied bits and pieces from the documentation and examples so I’m fully prepared that I’ve totally stuffed this up.

I’ve tested the signature with C# that works fine. So I has to be something in the Clarion code.

I’ve loaded a pfx file into my local store and is supposed to sign and hash a string with my private key USING RSA-SHA1.

Since I’ve got Capesoft Cryponite and NetTalk I’m trying to use those.

Here’s the code. I’m unsure if this is loading the private key but none of the first parts are generating any errors so I believe I’m good there. You can seem to specify to use RSA when signing the code but the verify does show my email address and “348” which I’m unsure about.

RESPONSE from XERO: oauth_problem=signature_method_rejected&oauth_problem_advice=Private%20applications%20must%20use%20the%20RSA-SHA1%20signature%20method

Which to me looks like the string was not properly signed and hashed.

    If Crypto.GetContainer('myETW', true) <> Crypto:OK
        Stop('Get Container Failed')
    End
    storeName = 'MY'                 
    CertificateName  = 'Bertus Viljoen'
    LOC:ConsumerKey.SetValue('PZI118TAMBCNHT7LNKINNUT7N85N5F')
    
    Result = Crypto:NotOK
    Store = Crypto.CertOpenSystemStore (StoreName)
  
    If Store
        CertContext = Crypto.CertFind (Store, clip(CertificateName))    
        If CertContext           
            Provider = Crypto.CertGetPrivateKey(CertContext, FreeKey)
            If Provider       
                Crypto.hProvider = Provider
                Result = Crypto.GetUserKey()
            End  
        End
    End      
    
    TimeStamp = (((Today()-61730)*86400)+(CLOCK()/100-36000))
  !           TimeStamp = 1559906676
  
  !        STOP(TimeStamp)
    
    LOC:Request.SetValue('oauth_consumer_key='&LOC:ConsumerKey.GetValue()&|
        '&oauth_nonce=471weirpow-0e06-4e0b-a97b-379878976671'&|
        '&oauth_signature_method=RSA-SHA1'&|
        '&oauth_timestamp='&TimeStamp&|
        '&oauth_token='&LOC:ConsumerKey.GetValue()&|
        '&oauth_version=1.0')
  
     LOC:AuthStr.SetValue('GET&https://api.xero.com/api.xro/2.0/Organisation&'&LOC:Request.GetValue())
  
    LOC:AuthStr.UrlEncode()
  !       Stop(LOC:AuthStr.GetValue())
  
    If Crypto.SignMessage(LOC:AuthStr,cs:CALG_SHA1,CertificateName,LOC:Signature,Crypto:EncBase64,True,True) <> Crypto:OK
        Stop('Sign message Failed')
    Else
        If Crypto.VerifySignature(LOC:AuthStr,LOC:Signature,Crypto:EncBase64,CertificateName,CertInfo,,Verified) = Crypto:NotOk
                  Case Verified
                  Of Crypto:NoProvider
                      Stop('If the message Crypto:NoProvider is not found')
                  Of Crypto:NTE_BAD_SIGNATURE
                      Stop('If the message Crypto:NTE_BAD_SIGNATURE is not found')
                  Of Crypto:NTE_BAD_ALGID
                      Stop('If the message Crypto:NTE_BAD_ALGID is not found')
                  Of Crypto:CRYPT_E_NO_SIGNER
                      Stop('If the message Crypto:CRYPT_E_NO_SIGNER is not found')
                  Of Crypto:CRYPT_E_UNEXPECTED_MSG_TYPE
                      Stop('If the message Crypto:CRYPT_E_UNEXPECTED_MSG_TYPE is not found')
                  Of Crypto:E_INVALIDARG
                      Stop('If the message Crypto:E_INVALIDARG is not found')
                  Of Crypto:CERTNOTTRUSTED 
                      Stop('If the certificate is marked as untrusted on the system (this is not implemented because it is application-specific) ')
        
                  Of Crypto:CERTEXPIRED 
                      Stop('If the certificate''s time validity check fails ')
        
                  Of Crypto:CERTREVOKED 
                      Stop('If the certificate is in the issuer''s CRL ')
        
                  Of Crypto:ISSUERSIGFAILED 
                      Stop('If the issuer signature on the certificate fails ')
        
                  Of Crypto:ISSUERCERTNOTFOUND 
                      Stop('If the issuer certificate not found on local machine ')
        
                  Of Crypto:MSG_CERTNOTFOUND 
                      Stop('If the message certificate is not found')
        
                  Of Crypto:MSG_ALTERED
                      Stop('If the message Crypto:MSG_ALTERED is not found')
                  Else
                      Stop(CLIP(CertificateName)&'<13,10>'&CLIP(Verified)&'<13.10>')
                  End
        End
    End
  !      Stop(LOC:Signature.GetValue())
  !   Crypto.EncryptString(LOC:AuthStr,'',,cs:PROV_RSA_FULL)
  !   Crypto.MakeHash(LOC:AuthStr,cs:CALG_SHA1)
  !  LOC:AuthStr.Base64Encode()
    
    
    XeroClient.SetAllHeadersDefault() 
    XeroClient.HeaderOnly = False
    XeroClient.AcceptEncoding = ''!'gzip,deflate'
    XeroClient.CanUseProxy = 0
    XeroClient.Authorization = 'Oauth oauth_consumer_key='&LOC:ConsumerKey.GetValue()&', oauth_nonce=471weirpow-0e06-4e0b-a97b-379878976671, oauth_signature='&Clip(LOC:Signature.GetValue())&|
              ', oauth_signature_method=RSA-SHA1, oauth_timestamp='&TimeStamp&',oauth_token='&LOC:ConsumerKey.GetValue()&',oauth_version=1.0' 
    XeroClient.ContentType = 'application/json; charset=utf-8'
    XeroClient.SSLMethod = NET:SSLMethodTLSv1_2       
  
    XeroClient.GET('https://api.xero.com/api.xro/2.0/organisation','')

Hi Bertus,

Not used Xero, NetTalk or Cryptonite but have done oAuth with other Clarion applications
(sending VAT Returns to UK HMRC) and for that I found Fiddler 4 to be a great help.

It’s free and can show you what’s happening in both normal and HTTPS traffic.

If as you say you can get Xero to work in C# but not in Clarion then I’d compare the Fiddler 4 trace from C# to that from Clarion and hopefully that will show up the problem(s).

Thanks Graham.

I already know that the signed, hashed string produced by Crypto is different from C#.

But I will give it a go.

Bertus

Hi Bertus,

Im not sure if it helps but we offer a wrapper class for the Chilkat Comms Library.

One if the parts of our product is a Task class for Xero, it makes connecting a single method call along with singles method calls to easily download and / or update various items within Xero (eg, Contacts, Invoices, Credit Notes, Currencies, Tax Rates etc etc)

As well as Xero, the other Task classes include QUickBooks Online, Dropbox, SMS, Easypost, D-Track, Google Events and Tasks amongst others.

Plus, it covers around 96 base classes like Oauth 1+2, Rest, JSon, XML, HTTP, Google, AWS etc

Feel free to contact us and I’ll arrange an online demo of it in action.

Thanks,

Andy
[email protected]

www.noyantis.com

Thanks Andy. I will have a look.