Reputation: 623
I am using the following: https://github.com/XeroAPI/xero-node
I am using a React app, talking to a Nodejs backend. The React app calls the node file connect.js as per the below:
// connect.js (node module)
const XeroClient = require('xero-node').XeroClient;
async function connect(req, res, next) {
try {
const xero = new XeroClient({
clientId: '9.............(hidden for SO)',
clientSecret: 'p...........(hidden for SO)',
redirectUris: [`http://localhost:3000/xeroCallback`],
scopes: 'openid profile email accounting.transactions offline_access'.split(" ")
});
let consentUrl = await xero.buildConsentUrl();
res.send(consentUrl);
} catch (err) {
console.log(err);
}
}
module.exports = connect;
This returns the URL to my React front end, which triggers a re-direct
This works fine, I am taking to the Xero Auth page, which then re-directs me back to localhost, where my React frontend calls on .callback.js from the back end, sending along the URL past from Xero:
{"http://localhost:3000/xeroCallback?code":"3......(hidden for SO)","scope":"openid profile email accounting.transactions","session_state":"E.........(hidden for SO)"}
Here is my code in callback.js
// callback.js (node module)
const { TokenSet } = require('openid-client');
const XeroClient = require('xero-node').XeroClient;
async function callback(req, res) {
const xero = new XeroClient({
clientId: '9.............(hidden for SO)',
clientSecret: 'p...........(hidden for SO)',
redirectUris: [`http://localhost:3000/xeroCallback`],
scopes: 'openid profile email accounting.transactions offline_access'.split(" ")
});
try {
await xero.initialize()
const TokenSet = await xero.apiCallback(req.body);
res.send(TokenSet);
} catch (err) {
console.log(err);
}
}
module.exports = callback;
There error is at "const TokenSet = await xero.apiCallback(req.body);" Gives me 'Access token undefined!"
Upvotes: 2
Views: 1170
Reputation: 2642
So the error is because the Xero client has not yet been properly initialized.
https://github.com/XeroAPI/xero-node/blob/master/src/XeroClient.ts#L99
As you can see on the code below (linked above) the callbackParams function is a method on the openIdClient ( an oauth2.0 library ) - in order to fully setup they client you will need to call either xero.initialize()
or xero.buildConsentUrl()
It also looks like you should be passing back the req.url, though the req.body might still work..
this.openIdClient.callbackParams(callbackUrl)
It is setup this way to allow for more varied use cases for folks who do not need/want to access the helpers by requiring the openid-client.
// This needs to be called to setup relevant openid-client on the XeroClient
await xero.initialize()
// buildConsentUrl calls `await xero.initialize()` so if you wont
// need to also call initialize() if you are sending user through auth
await xero.buildConsentUrl()
// You can also refresh the token without needing to initialize the openid-client
// helpful for background processes where you want to limit any dependencies (lambda, etc)
await xero.refreshWithRefreshToken(client_id, client_secret, tokenSet.refresh_token)
https://github.com/XeroAPI/xero-node
Upvotes: 4