Page 1 of 1

Working Example of oAuth and XERO

PostPosted: Sun Dec 28, 2014 7:13 pm
by d.pearce1417196993
Hi,

does anyone have a few snippets of code for authenticating with XERO accounts with or without the oAuth plugin.

Just doing some XMAS research whilst I have some downtime. I see some people have tried this, but I think the code snippets available appear to be after the initial requesting of authentication.

It would be a great shortcut if anyone has a couple of routines to do the authentication and then a basic call to XERO.

Thanks in advance

David

Re: Working Example of oAuth and XERO

PostPosted: Thu Jan 08, 2015 2:01 pm
by antonio
Hi David,

I use the oAuth plugin https://www.servoyforge.net/projects/oauth-plugin (but happy to be shown another way :-)

I've built methods for GET, POST and PUT, but you could collapse these into a generic method.
I'll post some examples of how I call these shortly.

Code: Select all
function OAuthXeroGET(vLive, vEndpoint, vAttributeName, vAccept) {
   try
   {
      if (!vAccept) // default to json for backwards compatability.
         vAccept = "json"
            
      vEndpoint = globals.UrlEncode(vEndpoint);
      plugins.oauth // initialise
      var oauth_api = OAuthAPI.XERO
      var client_id = vLive?gvClientId:gvClientIdDemo;
      var secret = vLive?gvSecret:gvSecretDemo   
      var resource_url = gvXeroURL + vEndpoint;
      var method = Methods.GET;
      var request = plugins.oauth.createOAuthRequest(oauth_api, client_id, secret, method);
      if (!request)
         throw "No request object returned"
      request.setResourceUrl(resource_url);
      request.setHeader("Accept","application/" + vAccept);
      request.execute();
      var response = request.getResponse();
      if (!response)
         return null

      if (vAccept == "xml" ||vAccept == "pdf")
      {
         var vContent = request.getResponse().getContent();
         return vContent
      }
      else if (vAccept == "json")
      {
         var vAttribute = response.getAttributeValue(vAttributeName)
         var json = eval('(' + vAttribute + ')')
         return json
      }
      else
         throw "OAuthXeroGET Unsupported content type " + vAccept
   }
   catch(e)
   {
      var vMsg = "OAuthXeroGET Error - " + e + "\nvEndpoint = " + vEndpoint + "\nvAttributeName = " + vAttributeName
      //...   
   }
}


Code: Select all
function OAuthXeroPOST(vLive, vEndpoint, vAttributeName, vXML, vAccept) {
   try
   {
      if (!vAccept) // XML in POST body, but want response as json for easy parsing.
         vAccept = "json";
      plugins.oauth // initialise
      var oauth_api = OAuthAPI.XERO
      var client_id = vLive?gvClientId:gvClientIdDemo;
      var secret = vLive?gvSecret:gvSecretDemo   
      var resource_url = gvXeroURL + vEndpoint;
      var method = Methods.POST;
      var request = plugins.oauth.createOAuthRequest(oauth_api, client_id, secret, method);
      request.setPostData("xml",vXML);
      request.setResourceUrl(resource_url);
      request.setHeader("Accept","application/" + vAccept);
      request.execute();
      var response = request.getResponse();
      if (!response)
         return null
      if (vAccept == "xml")
      {
         var vContent = request.getResponse().getContent();
         return vContent
      }
      else if (vAccept == "json")
      {
         var vAttribute = response.getAttributeValue(vAttributeName)
         var json = eval('(' + vAttribute + ')')
         return json
      }
      else
         throw "OAuthXeroPOST Unsupported content type " + vAccept
   }
   catch(e)
   {
      var vMsg = "OAuthXeroPOST Error - " + e + "\nvEndpoint = " + vEndpoint + "\nvAttributeName = " + vAttributeName + "\nvXML = " + vXML
      //...   
   }
}


Code: Select all
function OAuthXeroPUT(vLive, vEndpoint, vAttributeName, vXML, vAccept) {
   try
   {
      if (!vAccept)
         vAccept = "json"
      plugins.oauth // initialise
      var oauth_api = OAuthAPI.XERO
      var client_id = vLive?gvClientId:gvClientIdDemo;
      var secret = vLive?gvSecret:gvSecretDemo   
      var resource_url = gvXeroURL + vEndpoint;
      var method = Methods.PUT;
      var request = plugins.oauth.createOAuthRequest(oauth_api, client_id, secret, method);
      request.setPostData("xml",vXML);
      request.setResourceUrl(resource_url);
      request.setHeader("Accept","application/" + vAccept);      
      request.execute();
      var response = request.getResponse();
      if (!response)
         return null
      if (vAccept == "xml")
      {
         var vContent = request.getResponse().getContent();
         return vContent
      }
      else if (vAccept == "json")
      {
         var vAttribute = response.getAttributeValue(vAttributeName)
         var json = eval('(' + vAttribute + ')')
         return json
      }
      else
         throw "OAuthXeroPUT Unsupported content type " + vAccept
   }
   catch (e)
   {
      var vMsg = "OAuthXeroPUT Error - " + e + "\nvEndpoint = " + vEndpoint + "\nvAttributeName = " + vAttributeName + "\nvXML = " + vXML
      //...   
   }
}

Re: Working Example of oAuth and XERO

PostPosted: Fri Jan 09, 2015 12:24 am
by jasantana
Great stuff Antonio. Thank you very much. Just one question. Does the OAuth plugin works in SmartClient?
Thanks again

Re: Working Example of oAuth and XERO

PostPosted: Fri Jan 09, 2015 3:48 pm
by antonio
Yes, I just tried the plugin in SC in Dev environment, it works fine.
Here's an example of how I use the above code.

Code: Select all
function GetXeroInvoiceByID(vID) {
   // ID can be invoice number or UUID
   if (!vID)
      return
   var vLive = true      
   var vEndpoint = 'Invoices/' + vID
   var vAttributeName = "Invoices" // the part of the XML we want to get back
   var vResponse = globals.OAuthXeroGET(vLive, vEndpoint, vAttributeName, "xml")
   return vResponse // xml invoice object
}


Re: Working Example of oAuth and XERO

PostPosted: Sun Jan 11, 2015 9:16 pm
by jasantana
Thanks Antonio, we'll give a go to your samples

Re: Working Example of oAuth and XERO

PostPosted: Wed Nov 30, 2016 5:42 pm
by antonio
For some years I've been using the oAuth plugin (date stamped 08 March 2015) with the examples in this thread to connect with Xero. It's been working well with Java 6 and Servoy 5.2.16
I recently had to upgrade to Java 7 for TLS compatibility, and now I get the following error (full error log below).

Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

I tried the latest (Servoy 8) version with my Servoy 5.2.16 solution, but it doesn't appear under plugins in the Eclipse solution explorer.

Grateful for any tips on getting an oAuth connection working again, either using the plugin or with some other method. I've not in a position to change the solution from Servoy 5.2.16 any time soon.

Tony

org.scribe.exceptions.OAuthConnectionException: There was a problem while creating a connection to the remote service.
at org.scribe.model.Request.send(Request.java:69)
at org.scribe.model.Request.send(Request.java:75)
at com.donay.oauth.responses.ResponseFactory.create(ResponseFactory.java:23)
at com.donay.oauth.requests.JSOAuthRequest2Legged.js_execute(JSOAuthRequest2Legged.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:179)
at org.mozilla.javascript.NativeJavaMethod.call(NativeJavaMethod.java:353)
at org.mozilla.javascript.Interpreter.interpretLoop(Interpreter.java:3666)
at org.mozilla.javascript.Interpreter.interpret(Interpreter.java:2680)
at org.mozilla.javascript.InterpretedFunction.call(InterpretedFunction.java:166)
at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:387)
at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3135)
at org.mozilla.javascript.InterpretedFunction.call(InterpretedFunction.java:165)
at com.servoy.j2db.scripting.ScriptEngine.executeFunction(ScriptEngine.java:476)
at com.servoy.j2db.FormController.executeFunction(FormController.java:4003)
at com.servoy.j2db.FormController.executeFunction(FormController.java:3891)
at com.servoy.j2db.FormController.executeFunction(FormController.java:3813)
at com.servoy.j2db.FormController$ScriptExecuter.executeFunction(FormController.java:3668)
at com.servoy.j2db.ui.BaseEventExecutor.fireEventCommand(BaseEventExecutor.java:272)
at com.servoy.j2db.ui.BaseEventExecutor.fireEventCommand(BaseEventExecutor.java:242)
at com.servoy.j2db.ui.BaseEventExecutor.fireChangeCommand(BaseEventExecutor.java:173)
at com.servoy.j2db.server.headlessclient.dataui.WebDataComboBox$3.execute(WebDataComboBox.java:446)
at com.servoy.j2db.server.headlessclient.ServoyForm.processDelayedActions(ServoyForm.java:84)
at com.servoy.j2db.server.headlessclient.dataui.WebEventExecutor.onEvent(WebEventExecutor.java:352)
at com.servoy.j2db.server.headlessclient.dataui.WebEventExecutor.onEvent(WebEventExecutor.java:341)
at com.servoy.j2db.server.headlessclient.dataui.ServoyFormComponentUpdatingBehavior.onUpdate(ServoyFormComponentUpdatingBehavior.java:65)
at org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior.onEvent(AjaxFormComponentUpdatingBehavior.java:158)
at org.apache.wicket.ajax.AjaxEventBehavior.respond(AjaxEventBehavior.java:177)
at org.apache.wicket.ajax.AbstractDefaultAjaxBehavior.onRequest(AbstractDefaultAjaxBehavior.java:312)
at org.apache.wicket.request.target.component.listener.BehaviorRequestTarget.processEvents(BehaviorRequestTarget.java:157)
at org.apache.wicket.request.AbstractRequestCycleProcessor.processEvents(AbstractRequestCycleProcessor.java:92)
at org.apache.wicket.RequestCycle.processEventsAndRespond(RequestCycle.java:1279)
at org.apache.wicket.RequestCycle.step(RequestCycle.java:1358)
at org.apache.wicket.RequestCycle.steps(RequestCycle.java:1465)
at org.apache.wicket.RequestCycle.request(RequestCycle.java:545)
at org.apache.wicket.protocol.http.WicketFilter.doGet(WicketFilter.java:486)
at com.servoy.j2db.server.servlets.Zl.doGet(Zl.java:7)
at org.apache.wicket.protocol.http.WicketServlet.doPost(WicketServlet.java:160)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:567)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.Handshaker.activate(Handshaker.java:470)
at sun.security.ssl.SSLSocketImpl.kickstartHandshake(SSLSocketImpl.java:1438)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1308)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
at org.scribe.model.Response.<init>(Response.java:28)
at org.scribe.model.Request.doSend(Request.java:115)
at org.scribe.model.Request.send(Request.java:65)
... 55 more

I also note a small change in syntax in the oAuth plugin examples on servoyforge -

Old code
Code: Select all
      plugins.oauth // initialise
      var oauth_api = OAuthAPI.XERO

New code

Code: Select all
   var oauth_api = plugins.oauth.OAuthAPI.XERO;

Is that correct?

Re: Working Example of oAuth and XERO

PostPosted: Wed Nov 30, 2016 6:41 pm
by sbutler
That old code seems like it would never have worked. You can set a variable and do something similar, but this is essentially the same as the new code you have. The new code seems like it would be correct.

Code: Select all
var oauth = plugins.oauth;
var oauth_api = oauth.OAuthAPI.XERO;


Same as:

Code: Select all
var oauth_api = plugins.oauth.OAuthAPI.XERO;

Re: Working Example of oAuth and XERO

PostPosted: Wed Nov 30, 2016 11:09 pm
by antonio
thanks Scott, the new syntax does look better, but the old code worked fine, and curiously didn't work with out the initialize line.