3

I am using the Xero Api with Nodejs and the xero-node library.

I have completed the oAuth flow and saved the token to the database. The issue i am now having is continually getting a 403 forbidden error when attempting to get anything from Xero be that Contacts, Accounts or Users. Sample code is below

I can get tenants ok without an issue however anything else doesn't work. I have checked the scopes to make sure when I am setting up the client they are correct which they are.

var getStuff = async(tokenSet) => {
  await xero.setTokenSet(tokenSet);
  const tenants = await xero.updateTenants();

  const xeroTenantId = tenants[0].id  // {String} Xero identifier for Tenant
  const ifModifiedSince = new Date("2020-02-06T12:17:43.202-08:00");
  const where =  'IsSubscriber==true';  // {String} Filter by an any element
  const order =  'LastName ASC';  // {String} Order by an any element

  console.log(tenants);
  try {
    const response  = await xero.accountingApi.getUsers(xeroTenantId, ifModifiedSince, where, order);
    console.log(response.body || response.response.statusCode)

  }
  catch (err) {

   /// console.log(err);

    console.log(`There was an ERROR! \n Status Code: ${err.response.statusCode}.`);
    console.log(`ERROR: \n ${JSON.stringify(err.response.body, null, 2)}`);

  }

}

duckdivesurvive
  • 177
  • 1
  • 8

2 Answers2

5

Which scopes have been added to the access token you are passing through? You can decode your token here https://jwt.io/

Also - you need to pass the ‘tenant.tenantId’ to the function. I believe the tenant.id actually relates to the connection id which is coming back from the /connections endpoint.

My hunch is that is the issue. Also curious how that’s working, as updateTenants() should have the empty function call on the end. Is that working for you?

SerKnight
  • 2,502
  • 1
  • 16
  • 18
  • 1
    Ok i was about to delete this question as i worked it out. For some reason maybe its lockdown i just used ".id" , when what i should have been looking for was "tenantId" as you have correctly pointed out Thank you – duckdivesurvive May 21 '20 at 15:57
  • Common misconception. The concept of a connection differs a bit from a tenant in that regard. Glad you got it sorted :) – SerKnight May 22 '20 at 15:48
1

I have the same problem & after reviewing the official GitHub for .net standard I've found we need to send tenants[0].TenantId instead of tenants[0].id So you should use tenants[0].TenantId instead of tenants[0].id.

You could find more on https://github.com/XeroAPI/xero-node

import { XeroClient, HistoryRecords, Invoice } from 'xero-node';

const xero = new XeroClient({
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  redirectUris: [`http://localhost:${port}/callback`],
  scopes: 'openid profile email accounting.transactions offline_access'.split(" ")
});

await xero.initialize();

const tokenSet = getTokenSetFromDatabase(userId); // example function name

await xero.setTokenSet(tokenSet);

if(tokenSet.expired()){
  const validTokenSet = await xero.refreshToken();
  // save the new tokenset
}

await xero.updateTenants();

const activeTenantId = xero.tenants[0].tenantId;

// GET all Accounts
const getAccountsResponse = await xero.accountingApi.getAccounts(activeTenantId);
Tyler2P
  • 2,324
  • 26
  • 22
  • 31