github.com/rorycl/XeroOauthTokenServer

Local server to act as a Xero OAuth2 token proxy to help software migrating from Xero's OAuth1 flows


Keywords
golang, oauth2, oauth2-server, xero, xero-api
License
MIT
Install
go get github.com/rorycl/XeroOauthTokenServer

Documentation

xerooauthtokenserver

version 0.1.0 May 2022

Summary

XeroOauthTokenServer is an http server for managing OAuth2 tokens for the Xero accounting SaaS service. The server acts as a sidecar or proxy, allowing easy integration of Xero OAuth2 flows.

After taking the user through first a login screen for providing the Xero client id, client secret and tenant id, the programme then takes the user through the Xero Oauth2 flow. If this is successful, the server makes a json access token available at the /token endpoint, and will refresh tokens when required, or when the refresh token is due to expire.

The xerooauthtokenserver/token package makes it easy to integrate the Xero OAuth2 flow into a Go programme, including automated token refreshes.

Please note the security warnings set out in Security and Warranty below.

Usage

Ensure you have configured a Xero OAuth2 web app at https://developer.xero.com/app/manage and generated a client id and secret which will be needed for login, together with the relevant tenant id. It is important that one of the "Redirect URIs" is set to http://localhost:5001/code or the equivalent for your locally configured XeroOauthTokenServer server address if it is not at 127.0.0.1:5001.

Run the server which by default will run on http://127.0.0.1:5001 and follow the login and then Xero authentication flow. You can then extract a token at the /token endpoint, force a refresh at /refresh or view the server data at /livez.

./XeroOauthTokenServer

It is necessary to revoke a token (using the associated refresh token) to limit or expand scopes. If a different set of scopes is specified to that associated with a refresh token the programme will abort with an error.

The following endpoints are provided:

/        : add client credentials
/home    : commence the oauth2 flow after adding credentials
/code    : used as the redirect endpoint
/livez   : check service health
/status  : view the status of the services
/token   : view the current token
/refresh : force a refresh of the token
/tenants : view the tenants accessible with this token
/revoke  : revoke the token
/logout  : logout and revoke the token

Security and Warranty

It is not advisable to put this server on the public internet.

This server is only suitable for integration with software designed to act with the permissions of the user initialising it.

Please refer to the LICENSE and note that this software is provided without warranty of any kind.

Programme options

Usage:
  XeroOauthTokenServer  <options>

  Xero oauth token server : 0.1.0 May 2022

Application Options:
  -p, --port=        port to run on (default: 5001)
  -n, --address=     network address to run on (default: 127.0.0.1)
  -r, --redirect=    oauth2 redirect address (default: http://localhost:5001/code)
  -o, --scopes=      oauth2 scopes (default: offline_access, accounting.transactions,
                     accounting.reports.read)
  -m, --refreshmins= set lifetime of refresh token (default 50 days) (default: 72000)

Help Options:
  -h, --help         Show this help message

Integration

An integration example is provided in the examples directory of this repo, and reproduced below. The integration assumes xerooauthtokenserver is running on the default address and port. The integration is encapsulated by the get_token function.

"""
Python xerooauthtokenserver integration example
"""

import requests


def get_token():
    """retrieve token from xerooauthtoken server"""
    response = requests.get("http://127.0.0.1:5001/token")
    return response.json()['accessToken']


def tenants(access_token):
    """
    retrieve the id of the first tenant
    can also use "http://127.0.0.1:5001/tenants"
    """
    tenants_url = 'https://api.xero.com/connections'
    response = requests.get(
        tenants_url,
        headers={
            'Authorization': 'Bearer ' + access_token,
            'Content-Type': 'application/json'
        })
    return response.json()[0]["tenantId"]  # first tenant id


def invoices(access_token, tenant_id):
    """get invoices"""
    invoice_url = 'https://api.xero.com/api.xro/2.0/Invoices'
    response = requests.get(
        invoice_url,
        headers={
            'Authorization': 'Bearer ' + access_token,
            'Xero-tenant-id': tenant_id,
            'Accept': 'application/json'
        })
    return response.json()


if __name__ == '__main__':

    token = get_token()
    tenant = tenants(token)
    invoices = invoices(token, tenant)
    print(invoices)