UNPKG

11.1 kBMarkdownView Raw
1# xero-node
2![npm](https://img.shields.io/npm/v/xero-node?label=xero-node)
3
4## Release of SDK with oAuth 2 support
5Version 4.x of Xero NodeJS SDK only supports oAuth2 authentication and the following API sets.
6* accounting
7* assets
8
9### Bank feeds support in OAuth 2
10An early release in a separate package is availalbe [bank feeds API](https://github.com/XeroAPI/xero-node-bankfeeds).
11
12## Looking for OAuth 1.0a support?
13[![npm package](https://img.shields.io/badge/npm%20package-3.1.2-blue.svg)](https://www.npmjs.com/package/xero-node/v/3.1.2)
14
15We've moved this code into the [oauth1 branch](https://github.com/XeroAPI/xero-node/tree/oauth1).
16
17## Getting Started
18
19### Create a Xero App
20Follow these steps to create your Xero app
21
22* Create a [free Xero user account](https://www.xero.com/us/signup/api/) (if you don't have one)
23* Login to [Xero developer center](https://developer.xero.com/myapps)
24* Click "New App" link
25* Enter your App name, company url, privacy policy url.
26* Enter the redirect URI (this is your callback url - localhost, etc)
27* Agree to terms and condition and click "Create App".
28* Click "Generate a secret" button.
29* Copy your client id and client secret and save for use later.
30* Click the "Save" button. You secret is now hidden.
31
32## Repo Context & Contributing
33This SDK's functionality is majority generated [from our OpenAPISpec](https://github.com/XeroAPI/Xero-OpenAPI).
34The exception is the `src/xeroClient.ts` which contains the typescript that is unique to this repository. Contributions are welcome but please keep in mind that majority of SDK is auto-generated from the OpenAPISpec. We try to get changes in that projects to be released on a reasonable cadence.
35
36> Read more about our process in [maintaining our suite of SDK's](https://devblog.xero.com/building-sdks-for-the-future-b79ff726dfd6)
37
38## Testing
39We are working to build out a more robust test suite, and currently just have tests setup for our xeroClient.ts - PR's will now run against a CI build - and as we add more tests to this project community collaboration will be easier to incorporate.
40
41```
42npm test
43```
44
45## Authentication
46
47We use [OAuth2.0](https://oauth.net/2) to generate access tokens that authenticate requests against our API. Each API call will need to have a valid token populated on the API client to succeed. In a tokenSet will be an *access_token* which lasts for 30 minutes, and a *refresh_token* which lasts for 30 days. If you don't want to require your users to re-authenticate each time you want to call the API on their behalf, you will need a datastore for these tokens and will be required to refresh the tokens at least once per 30 days to avoid expiration. The `offline_access` scope is required for refresh tokens to work.
48
49In Xero a user can belong to multiple organisations. Tokens are ultimately associated with a Xero user, who can belong to multiple tenants/organisations. If your user 'Allows Access' to multiple organisations, be hyper aware of which `tenantId` you are passing to each function.
50
51---
52
53**Step 1:** Initialize the `XeroClient`, and redirect user to xero auth flow
54
55**Step 2:** Call `apiCallback` to get your tokenSet
56
57**Step 3:** Call `updateTenats` to populate additional tenant data
58
59---
60
61## Step 1
62* Configure client and generate Authorization URL
63* Choose [XeroAPI Scopes](https://developer.xero.com/documentation/oauth2/scopes) based on the access you need
64* `initialize()` the client to set up the 'openid-client'
65* Build the `consentUrl`
66* Redirect to auth flow
67```js
68const port = process.env.PORT || 3000
69
70const xero = new XeroClient({
71 clientId: 'YOUR_CLIENT_ID',
72 clientSecret: 'YOUR_CLIENT_SECRET',
73 redirectUris: [`http://localhost:${port}/callback`],
74 scopes: 'openid profile email accounting.transactions offline_access'.split(" ")
75});
76
77// `buildConsentUrl()` calls `await xero.initialize()`
78let consentUrl = await xero.buildConsentUrl();
79
80res.redirect(consentUrl);
81```
82
83## Step 2
84Call `apiCallback` function with the response url which returns a tokenSet you can save in your datastore for future calls.
85
86*The `tokenSet` can also be accessed from the client as `xero.readTokenSet()`.*
87
88```js
89
90const { TokenSet } = require('openid-client');
91
92const tokenSet: TokenSet = await xero.apiCallback(req.url);
93```
94The `tokenSet` is what you should store in your database. That object is what you will need to pass to the client. It contains your access_token and refresh_token as well as other information regarding your connection.
95```js
96{
97 id_token: 'eyJhxxxx.yyy',
98 access_token: 'eyJxxx.yyy.zzz',
99 expires_at: 1231231234,
100 token_type: 'Bearer',
101 refresh_token: 'xxxyyyyzzz',
102 scope: 'openid profile email accounting.settings accounting.reports.read accounting.journals.read accounting.contacts accounting.attachments accounting.transactions offline_access',
103 session_state: 'xxx.yyy'
104}
105```
106
107## Step 3 (convenience step)
108
109Populate the XeroClient's active tenant data
110
111For most integrations you will always want to display the org name and additional metadata about the connected org. The `/connections` endpoint does not currently serialize that data so requires developers to make additional api calls for each org that your user connects to surface that information.
112
113The `updatedTenants` function will query & nest the additional orgData results in your xeroClient under each connection/tenant object and return the array of tenants. This requires `accounting.settings` scope because `updateTenants` calls the organisation endpoint.
114
115```js
116const tenants = await xero.updateTenants()
117
118console.log(tenants || xero.tenants)
119[
120 {
121 id: 'xxx-yyy-zzz-xxx-yyy',
122 tenantId: 'xxx-yyy-zzz-xxx-yyy',
123 tenantType: 'ORGANISATION',
124 createdDateUtc: 'UTC-DateString',
125 updatedDateUtc: 'UTC-DateString',
126 orgData: {
127 organisationID: 'xxx-yyy-zzz-xxx-yyy',
128 name: 'My first org',
129 version: 'US',
130 shortCode: '!2h37s',
131 ...
132 }
133 },
134 {
135 id: 'xxx-yyy-zzz-xxx-yyy',
136 tenantId: 'xxx-yyy-zzz-xxx-yyy',
137 tenantType: 'ORGANISATION',
138 createdDateUtc: 'UTC-DateString',
139 updatedDateUtc: 'UTC-DateString',
140 orgData: {
141 organisationID: 'xxx-yyy-zzz-xxx-yyy',
142 name: 'My second org',
143 version: 'AUS',
144 shortCode: '!yrcgp',
145 ...
146 }
147 }
148]
149```
150
151---
152## Making **offline_access** calls
153
154Once you have a valid token/tokenSet saved you can set the tokenSet on the client without going through the callback by calling `setTokenSet`.
155
156For example - once a user authenticates you can refresh the token (which will also set the new token on the client) to make authorized api calls.
157
158There are two ways to refresh a token.
159
160```js
161// refreshToken()
162const validTokenSet = await xero.refreshToken()
163```
164
165If you already generated a valid access token, you can initialize an empty client and refresh any saved access_tokens by passing the client, secret, and refresh_token to refreshWithRefreshToken()
166```js
167const newXeroClient = new XeroClient()
168const refreshedTokenSet = await newXeroClient.refreshWithRefreshToken(client_id, client_secret, tokenSet.refresh_token)
169```
170
171Making AUthorized API calls:
172
173```js
174const tokenSet = getTokenSetFromDatabase(userId) // example function name
175
176await xero.setTokenSet(tokenSet)
177
178// you can call this to fetch/set your connected tenant data on your client, or you could also store this information in a database so you don't need to updateTenants every time you connect to API
179await xero.updateTenants()
180
181await xero.accountingApi.getInvoices(xero.tenants[0].tenantId)
182```
183
184## SDK Documentation
185* Version 3 (OAuth1.0a documentation) https://xeroapi.github.io/xero-node/v3/index.html (*deprecated end of 2020*)
186* Accounting API documentation: https://xeroapi.github.io/xero-node/v4/accounting/index.html
187* Assets API documentation: https://xeroapi.github.io/xero-node/v4/assets/index.html
188* Projects API documentation: https://xeroapi.github.io/xero-node/v4/projects/index.html
189
190### Basics
191```js
192// example flow of initializing and using the client after someone has already authenticated and you have saved their tokenSet
193const xero = new XeroClient({
194 clientId: 'YOUR_CLIENT_ID',
195 clientSecret: 'YOUR_CLIENT_SECRET',
196 redirectUris: [`http://localhost:${port}/callback`],
197 scopes: 'openid profile email accounting.transactions offline_access'.split(" ")
198});
199await xero.initialize();
200
201const tokenSet = getYourTokenSetFromSavedLocation(currentUser)
202
203await xero.setTokenSet(tokenSet)
204...
205
206const activeTenantId = xero.tenants[0].tenantId
207
208const getOrgs = await xero.accountingApi.getOrganisations(activeTenantId)
209const orgCountry= getOrgs.body.organisations[0].countryCode
210
211const contactsResponse = await xero.accountingApi.getContacts(activeTenantId)
212const contactId = getContactsResponse.body.contacts[0].contactID
213
214---
215import { XeroClient, Invoice } from "xero-node";
216
217const invoices = {
218 invoices: [
219 {
220 type: Invoice.TypeEnum.ACCREC,
221 contact: {
222 contactID: contactId
223 },
224 lineItems: [
225 {
226 description: "Acme Tires",
227 quantity: 2.0,
228 unitAmount: 20.0,
229 accountCode: "500",
230 taxType: "NONE",
231 lineAmount: 40.0
232 }
233 ],
234 date: "2019-03-11",
235 dueDate: "2018-12-10",
236 reference: "Website Design",
237 status: Invoice.StatusEnum.AUTHORISED
238 }
239 ]
240};
241
242const createdInvoice = await xero.accountingApi.createInvoices(activeTenantId, invoices)
243```
244
245# Sample App
246For more robust examples in how to utilize our accounting api we have *(roughly)* every single endpoint mapped out with an example in our sample app - complete with showing the Xero data dependencies required for interaction with many objects ( ie. types, assoc. accounts, tax types, date formats).
247
248Just visit the repo https://github.com/XeroAPI/xero-node-oauth2-app configure your credentials & get started.
249
250## Other Helper functions
251```js
252// xero.tenants
253xero.tenants
254
255// initialize()
256// This needs to be called to setup relevant OAuth2.0 information on the client
257await xero.initialize()
258
259// buildConsentUrl()
260// This calls `await xero.initialize()` so you don't need to call initialize if you are using this function to send someone through auth flow
261await xero.buildConsentUrl()
262
263// readTokenSet()
264const tokenSet = await xero.readTokenSet();
265
266// tokenSet.expired()
267if (tokenSet.expired()) {
268 // refresh etc.
269}
270
271// refreshToken()
272const validTokenSet = await xero.refreshToken()
273
274// refreshWithRefreshToken()
275await xero.refreshWithRefreshToken(client_id, client_secret, tokenSet.refresh_token)
276
277// disconnect()
278await xero.disconnect(xero.tenants[0].id)
279
280// readIdTokenClaims()
281await xero.readIdTokenClaims()
282
283// readTokenSet()
284await xero.readTokenSet()
285
286// setTokenSet(tokenSet)
287const tokenSet = await xero.readTokenSet()
288await xero.setTokenSet(tokenSet)
289```