Closed dbowmanDT closed 3 years ago
Could you provide the Request Payload
and Response headers
if possible?
Request was to the sandbox environment:
/v3/company/
Encoded url looks like this: https://sandbox-quickbooks.api.intuit.com//v3/company/4620816365048034790/query?query=%20select%20Name%2C%20Id%20from%20Item%20Where%20Type%20%3D%20'Service'%20and%20Name%20like%20'%25'%20startposition%200%20maxresults%2011
I do not have the response headers, I should have put them in the issue when I encountered the error. I do not know how to reproduce consistently.
@dbowmanDT : The query that was passed to the makeApiCall()
was not URI-encoded.
The query you are trying to use is :
select Name, Id from Item Where Type = 'Service' and Name like '%' startposition 0 maxresults 11
You can pass the query using makeApiCall()
as shown below : ( minorversion is optional )
makeApiCall({
url: `${url}v3/company/${companyID}/query?query=select%20Name%2C%20Id%20from%20Item%20Where%20Type%20%3D%20%27Service%27%20and%20Name%20like%20%27%25%27%20startposition%200%20maxresults%2011&minorversion=51`,
})
For now, you can use the above-mentioned workaround.
Since this is an OAuth2.0
library, we will think about how to add this to a full-fledged SDK.
@abisalehalliprasan I am already properly encoding the URI when it was sent and got the error in question.
I provided the encoded and non-encoded query in my comment for your convenience.
@abisalehalliprasan @dbowmanDT I am also facing the same issue, I digged into the source code and the problem was in the processresponse
method.
AuthResponse.prototype.processResponse = function processResponse(response) {
this.response = response || '';
this.body = (response && response.body) || '';
this.json = this.body ? JSON.parse(this.body) : null; // JSON.parse is failing.
this.intuit_tid = (response && response.headers && response.headers.intuit_tid) || '';
};
the response body value returned as follows,
body: '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><IntuitResponse xmlns="http://schema.intuit.com/finance/v3" time="2020-08-17T02:01:11.228-07:00"><Fault type="AuthenticationFault"><Error code="100"><Message>General Authentication Error</Message><Detail>AuthenticationErrorGeneral: SRV-110-Authentication Failure , statusCode: 401</Detail></Error></Fault></IntuitResponse>'
As the body is returned in xml it is failing in process response.
Also, I make api call only if the oauthClient.isAccessTokenValid()
returns true. However there is authentication error. Am I missing some thing?
the query is select * from Account where AccountType = 'Cost of Goods Sold'
Please help.
@akila-arasan : Tried to reproduce the error and I am not running into the same issue. I am suspecting if there is a mismatch with the Base URL used to make the API call and the Keys provided. When a token is invalid the SDK throws an error with the below format ( secure details are masked )
authResponse: AuthResponse {
token: Token {
realmId: '462xxxxxxxxxxx867780',
token_type: 'bearer',
access_token: 'eyJlbmMixxxxxxxxxxxxxFFxk-hjxtA',
refresh_token: 'AB11606448419RxxxxxxxxxxxxxxxxxxxxgRlWpTn0xFffVpoq',
expires_in: 3600,
x_refresh_token_expires_in: 8726400,
id_token: '',
latency: 60000,
createdAt: 1597722019184,
state: 'intuit-test'
},
response: Response {
Url: [Url],
rawHeaders: [Array],
body: '{"warnings":null,"intuitObject":null,"fault":{"error":[{"message":"message=AuthenticationFailed; errorCode=003200; statusCode=401","detail":"Could not decrypt JWT.","code":"3200","element":null}],"type":"AUTHENTICATION"},"report":null,"queryResponse":null,"batchItemResponse":[],"attachableResponse":[],"syncErrorResponse":null,"requestId":null,"time":1597722025429,"status":null,"cdcresponse":[]}',
status: 401,
statusText: 'Unauthorized'
},
body: '{"warnings":null,"intuitObject":null,"fault":{"error":[{"message":"message=AuthenticationFailed; errorCode=003200; statusCode=401","detail":"Could not decrypt JWT.","code":"3200","element":null}],"type":"AUTHENTICATION"},"report":null,"queryResponse":null,"batchItemResponse":[],"attachableResponse":[],"syncErrorResponse":null,"requestId":null,"time":1597722025429,"status":null,"cdcresponse":[]}',
json: {
warnings: null,
intuitObject: null,
fault: [Object],
report: null,
queryResponse: null,
batchItemResponse: [],
attachableResponse: [],
syncErrorResponse: null,
requestId: null,
time: 1597722025429,
status: null,
cdcresponse: []
},
intuit_tid: '1-5f3b4da9-087a28ed878e2215f4eb3a28'
},
originalMessage: 'Response has an Error',
error: 'Unauthorized',
error_description: 'Unauthorized',
intuit_tid: '1-5f3b4da9-087a28ed878e2215f4eb3a28'
}
Could you share the sample code snippet where you are performing the query select * from Account where AccountType = 'Cost of Goods Sold'
that would help us debug the question at hand?
OR
if you could provide the intuit_tid / appID and timestamp of the request I could run by the logs to see what is missing.
@abisalehalliprasan Thanks for debugging.
The Base URL that I use to make the query is - https://sandbox-quickbooks.api.intuit.com/v3/company/realmId/query?query= select * from Account where AccountType = 'Cost of Goods Sold'
After establishing a connection between QB and our app, we try to export items to inventory, we need to check if the company has a income / expense account before adding items to inventory, that's why we make the above call.
the code snippet for the above api call is
const accountNameList = await oauthClient.makeApiCall({
url: `${QBUrl}v3/company/${realmId}/query?query=${query}`,
})
.then((res) => {
customSetToken(oauthClient, res.token);
return res;
})
.catch(function(err) {
return err;
})
the realmID is - 4620816365033885370
timestamp - 1597738603040
But the question here is oauthClient.isAccessTokenValid()
call returns true
only after that I make the call to query account. So if there is an authentication failure shouldn't this oauthClient.isAccessTokenValid()
fail?
I Logged the request, the code fails in the following method in sdk,
OAuthClient.prototype.getTokenRequest = function getTokenRequest(request) {
console.log('request', request);
const authResponse = new AuthResponse({ token: this.token });
return (new Promise(((resolve) => {
resolve(this.loadResponse(request));
}))).then((response) => {
authResponse.processResponse(response);
if (!authResponse.valid()) throw new Error('Response has an Error');
return authResponse;
}).catch((e) => {
if (!e.authResponse) e = this.createError(e, authResponse);
throw e;
});
};
The request object consoled was like this,
{
url: 'https://sandbox-quickbooks.api.intuit.com/v3/company/4620816365033885370/query?query=SELECT * FROM Account where AccountType = \'Cost of Goods Sold\'',
method: 'GET',
headers:
{ Authorization: 'Bearer xxxxxxxx',
Accept: 'application/json',
'User-Agent': 'Intuit-OAuthClient-JS_[object Object]_Darwin_19.4.0_darwin'
} }
I looked up our logs based on the realmID and timestamp you provided. It looks like you are making the call for an incorrect realm. The realm from the logs for the specific error shows ( 193514846595064 ) for the exact timestamp you provided.
And hence the oauthClient.isAccessTokenValid()
is returning true
as the token is still valid. ( under 1 hour duration )
I was able to reproduce the same error with the incorrect token/realm combination as shown below :
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3" time="2020-08-18T21:08:26.926-07:00">
<Fault type="AuthenticationFault">
<Error code="100">
<Message>General Authentication Error</Message>
<Detail>AuthenticationErrorGeneral: SRV-110-Authentication Failure , statusCode: 401</Detail>
</Error>
</Fault>
</IntuitResponse>
Could you verify if your application is able to associate the token object with realmID based on the storage mechanism that you are using? This should hopefully fix the issue.
As for the above error format XML handling, I will put in a PR for the next release.
@abisalehalliprasan Thanks ! The problem was in the cron that refreshes expired QB access tokens. Now the associations are correct.
Awesome. I will mark it as resolved. 👍
Hi @abisalehalliprasan do you have a timetable for when you plan to submit the PR for this issue? Our team would like to test our app with this AuthReponse JSON fix and plan accordingly. Thank you.
Has this been resolved?
Plugin Version: 3.0.1
Calling the makeApiCall function threw this error.
Error: Processing a request Error: AuthResponse is not JSON at AuthResponse.getJson (/home/dbowman/dtr-code/beacon/node_modules/.pnpm/registry.npmjs.org/intuit-oauth/3.0.1/node_modules/intuit-oauth/src/response/AuthResponse.js:106:29) at OAuthClient.createError (/home/dbowman/dtr-code/beacon/node_modules/.pnpm/registry.npmjs.org/intuit-oauth/3.0.1/node_modules/intuit-oauth/src/OAuthClient.js:571:31)
Looks like the response returned from QBO API was not JSON content.
Please advise.