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)