Using the Xero OAuth 2.0 API from a .NET Core console application

Xero logo

This is not a post about SQL Server, but I need to write about something that I’ve been struggling with for a number of weeks so that other people don’t have to.

A few months ago Xero announced that they would be moving their API authentication mechanism to OAuth 2.0. This is good news for a number of reasons. For developers and maintainers of apps that connect to Xero, we are no longer restricted to two private apps, nor do we need to worry about certificate files that expire unexpectedly. From Xero’s side this makes their API management more centralized.

The basic principle of OAuth 2.0 is that you have to log in somewhere, at which point you are issued an access token. The access token will have an expiration date, but you can extend that expiration by refreshing the access token using a refresh token which is provided at the same time.

In some implementations of OAuth 2.0 you can log in automatically without human interaction (i.e. clicking a button), but in Xero’s case the first time you generate tokens it has to be done through a web browser, and you have to click on a button. I’ve seen this with other implementations as well, and for the record I am not a fan.

With Xero’s new OAuth 2.0 authentication procedure you get an access token with a 60-day validity and a 30-minute timeout between refreshes. That means if you can automatically refresh the token within 60 days, you don’t need to keep logging in with the browser. This is a reasonable compromise given that access tokens tend to have a 30-day expiration, but of course Xero is in the accounting business and some months have 31 days.

For one of my companies I maintain a console application — recently ported from .NET Framework to .NET Core — that generates invoices in Xero once a month with no human interaction. As long as I can get an initial set of valid tokens into the app when I first run it, it will be able to run every month as needed without any further interaction, provided that I request the “offline access” policy when I generate the tokens (which is part of the authorization “scope”).

Unfortunately there is no single piece of documentation on how to access and use Xero’s new API if you’re using a .NET Core console application. All of their .NET code samples are based on ASP.NET Core, which assumes a significant number of things that just don’t apply to the console environment.

Here’s a quick primer to explain how I got it to work (with a little help from my friend and colleague Werner):

Step 1: Download xoauth

You need to get xoauth from the Xero repository on GitHub. When I first tried running it on my MacBook it didn’t work and I kept getting TLS timeout errors. One of the things my colleague suggested was using the version from Homebrew instead, which ended up working a lot better.

Step 2: Create an App on the Xero Developer portal

Visit My Apps and add a new app. I followed the instructions to create a web app (as opposed to a mobile or desktop app) as my console application is only being run on one machine, so I am less worried about the security of the client secret. If you’re building a console app that your customers will use, you must choose the mobile or desktop app with PKCE instead.

For the callback URL I used http://localhost:8080/callback because that’s what xoauth is expecting. Remember that you will use xoauth to generate the initial tokens that are used by your application, and thereafter the application itself will refresh the tokens as needed.

Step 3: Configure xoauth to use the new app

The instructions from the xoauth page are fairly straightforward. I chose Authorisation code when configuring my app using xoauth setup. One of the things my colleague noted is that there is a bug with the scope entry. Instead of having a space-delimited list of scope requests, you need to type them one by one, followed by the letter d to indicate that you’re done. Remember here to ask for offline_access.

You can see the full documentation for the scopes you need from the developer documentation.

Step 4: Fetch tokens for the new app using xoauth

When I used xoauth connect my browser opened, I signed into my organization and clicked on the button to agree to the request. Once that happened both the browser and xoauth showed me the tokens I needed for the initial connection, which I could then copy and paste into a file.

Note: You can also refresh tokens from the command line using xoauth token <appname> --refresh

Step 5: Profit

This is where the process broke down for me in two separate ways, and in both cases by a lack of documentation.

For starters, if you use the sample application provided by Xero, it’s a web application. If you follow the process flow and run the app you get a web interface, and when you click through and get the tokens a file is persisted to your drive containing a token object in JSON format. On the other hand, if you don’t want to build a web app and just want to retrofit a console app that already exists, there is no token file to modify with the output from xoauth.

I couldn’t find a sample token file anywhere in the Xero documentation, so I had to mock up one of my own using information from the API in the Visual Studio object browser and the XeroToken entity. This is how it looks (I’ve redacted the GUIDs and tokens for obvious reasons):

This is where I need to point out a bug, which was the first stumbling block in getting my code to run.

If you visit to get your list of tenants, the JSON is returned in traditional JSON format known as camel case, meaning that the first letter in the JSON object name is lower case (for example tenantId, tenantType, tenantName, and so on). However the API deserializer expects most of the names in Pascal case, meaning that the first letter is capitalized (see the sample above). That was fun to troubleshoot. A few JSON decorators in the API deserializer code wouldn’t go amiss is all I’m saying.

Once you have faked up a token file and placed it with your code, you now need an HttpClient to call the API to refresh tokens using the RefreshAccessTokenAsync() method.

This was the second major problem I faced, except now it was with .NET Core specifically. Microsoft really wants you to use IHttpClientFactory in your code, which is extreme overkill for doing a simple HTTP request, especially if you’re using a console application. The alternative is to use HttpClient, but that has a known issue with socket exhaustion because people don’t use it correctly. In the end I followed the instructions to use a SocketsHttpHandler with a PooledConnectionLifetime of 20 minutes (more here). This allows the use of a shared HttpClient across the lifetime of the app.


Once you have all those pieces together then it works as expected.

Getting to that point took me many hours of stress and swearing at my computer, on Twitter, in emails to the support team, and in a survey that I coincidentally received that week. Honestly it shouldn’t have. I’m still not happy, but hopefully this will help someone in the future avoid all of the pain and annoyance of poorly-conceived documentation that makes assumptions about the developer.

This post is already over 1200 words long, so I’ll stop here. I might be tempted to put together a sample app on GitHub that mimics the ASP.NET Core version, but I’m not there yet.

Share your thoughts in the comments below.

3 thoughts on “Using the Xero OAuth 2.0 API from a .NET Core console application

  • Sounds like their API needs an API on top of it for the JSON decorating :P. But yikes… the API should be designed to make life easier for you, not harder. And lack of good documentation is a huge pitfall for them. i remember working with a tool that had horrid API documentation. From sample code that was broken to functions that had the completely wrong description and arguments.
    If that was me, future me would probably go in and want to change the code and slowly realize that it is already in a good state and to stop messing with a good thing!
    Found that “bad example” in a Microsoft tool the other day too – Defrag. run “defrag /?” in Windows 10 (at least on 2004… not sure if it exists in other builds, but probably) and look at the examples. One example is “Defrag C:\mountpoint /Analysis /U”, but if you scroll up and look at the arguments, “Analysis” isn’t one of them. The proper one is “/Analyze”. Now, since most people are running SSD’s and aren’t running defrag, I expect that this won’t get fixed, but I should report that one…
    thanks for sharing your experience too! I so far have not had to deal with Oath2 in any of my apps, but that is because I’ve never built anything that needed extra authentication.

    • Hi Andrew, nothing yet that I can put on GitHub, but if you email me, I’ll see what I can share with you. info at this domain should do it.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: