It is possible to read data from the Xero API using Classic ASP, there’s little online at all to help you, other than a couple of cryptic hints, including this post which was the start of my adventure. Only problem being it refers to a Git repo which the files have vanished from.
Before you proceed, please note, you must have the Chilikat activeX COM installed – which I’d heartily recomend anyway, it’s the Swiss Army Knife for Classic ASP development, I’ve used Chilikat for everything from reading email from Gmail accounts, to reading/writing CSV files, to encrypting/decrypting data.
Let’s walk through the steps.
Create a public/private key pair
You’re going to need a public/private key pair, Xero has good instructions on creating these. I’m on a Mac so I can use openSSL, you can skip the creation of the pfx file as we only need the cer and the pem files.
openssl genrsa -out privatekey.pem 1024 openssl req -new -x509 -key privatekey.pem -out publickey.cer -days 1825
You’ll need to place the PEM file somewhere that can be read by your ASP code, so it’ll need to be in a folder on your server. The cer file you’ll need when registering your application in Xero.
Register a Xero Application
As part of registering your account you will upload your cer public key file. Once the application is registered you’ll see a Consumer Key value – grab that, you will need it later. Ignore the Consumer Secret, we’re not using this.
Call the Xero API
Here’s the code I use to obtain a list of all the invoices in my Xero account. I’ve tried to add full comments to explain what is happening.
My starting point for my adventure was a post in the Xero Community ‘Has anyone managed to get the API working using Classic ASP?‘. And my thanks to Ben Snape who even though his ASP solution had vanished from Github, still pointed me in the right direction, and I’ve borrowed his encoding and timestamp functions.
Quick explanation of a couple of things:
- The nonce value is a one time number, basically you just need to send a unique number each time. I’ve gone with a simple random number.
- The timestamp is a standard epoch number – just remember to shift your local time to UTC before generating, I’m 11 hours ahead of UTC at the moment on my local machine so you’ll need to adjust to suit your server (My production servers are UTC, I’ll tweak my code eventually to cope with the fact it’s UTC on production but not UTC on my local).
- It’s is correct you use the consumer key for both the oauth_consumer_key and oauth_token parameters.
<% Dim consumerKey,url,respText,params,crypt,baseSignature,pkey,success,rsa,signature,pkeyXml,hexSig dim objXMLHTTP ' URL to get a list of my invoices url="https://api.xero.com/api.xro/2.0/Invoices" ' your consumer key provided by Xero when you register your application consumerKey = "[Your Xero consumer key]" ' we need a random number (or a unique number) for every call - that's the nonce value Randomize ' build the parameters params="" params = params & "oauth_consumer_key="&consumerKey params = params & "&oauth_nonce="&int((9999999-99999+1)*rnd+99999) params = params & "&oauth_signature_method=RSA-SHA1" params = params & "&oauth_timestamp="&makeTimeStamp() params = params & "&oauth_token="&consumerKey ' this is the string we will make a signature from baseSignature = "GET&"&encode(url)&"&"&encode(params) response.write baseSignature&"<hr>" ' Load the private key from the RSA PEM file ' Using example from https://www.example-code.com/asp/rsa_signWithPEM.asp set pkey = Server.CreateObject("Chilkat_9_5_0.PrivateKey") success = pkey.LoadPemFile(server.MapPath("keys/privatekey.pem")) If (success <> 1) Then Response.Write "<pre>" & Server.HTMLEncode( rsa.LastErrorText) & "</pre>" Response.End End If ' Get the private key in XML format pkeyXml = pkey.GetXml() set rsa = Server.CreateObject("Chilkat_9_5_0.Rsa") success = rsa.UnlockComponent("[Your unlock code]") 'important, need to unlock ' Import the private key into the RSA component success = rsa.ImportPrivateKey(pkeyXml) If (success <> 1) Then Response.Write "<pre>" & Server.HTMLEncode( rsa.LastErrorText) & "</pre>" Response.End End If ' we want a base64 output NOT hex rsa.EncodingMode = "base64" rsa.LittleEndian = 0 signature = rsa.SignStringENC(baseSignature,"sha-1") Response.Write "<pre>" & Server.HTMLEncode( rsa.LastErrorText) & "</pre>" response.write "signature="&signature&"<Hr>" ' add the signature to the parameters params = params & "&oauth_signature="&encode(signature) response.write "params="¶ms&"<Hr>" ' add params to the url url=url&"?"¶ms response.write url&"<hr>" ' fire this at Xero set objXMLHTTP = Server.CreateObject("Msxml2.ServerXMLHTTP.6.0") objXMLHTTP.Open "GET", url, False objXMLHTTP.SetRequestHeader "Content-Type","application/json" objXMLHTTP.Send() respText=objXMLHTTP.ResponseText response.write respText&"<hr>" set objXMLHTTP=nothing Function makeTimeStamp() Dim dteFrom : dteFrom = "01/01/1970 00:00:00 AM" Dim dteNow : dteNow = Now() dteNow = DateAdd("n", -(11*60), dteNow) ' shift back 11 hours to UTC makeTimeStamp = DateDiff("s", dteFrom, dteNow) End Function Public Function encode(s) if s <> "" then Dim strTmpVal : strTmpVal = s Dim strRetVal : strRetVal = "" Dim intAsc : intAsc = 0 Dim strHex : strHex = "" Dim i, strChr : For i = 1 To Len(strTmpVal) strChr = Mid(strTmpVal, i, 1) If InStr(1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~", strChr) = 0 Then intAsc = Asc(strChr) If intAsc < 32 Or intAsc > 126 Then strHex = encodeURIComponent(strChr) Else strHex = "%" & Hex(intAsc) End If strRetVal = strRetVal & strHex Else strRetVal = strRetVal & strChr End If Next encode = strRetVal else encode = "" end if End Function %>