Intuit OAuth2.0 NodeJS Library
The OAuth2 Nodejs Client library is meant to work with Intuit's
OAuth2.0
and
OpenID Connect
implementations which conforms to the specifications.
Table of Contents
Requirements
The Node.js client library is tested against the Node 10
and newer versions.
Note: Older node versions are not supported.
Installation
Follow the instructions below to use the library :
Using NodeJS
-
Install the NPM package:
npm install intuit-oauth --save
-
Require the Library:
const OAuthClient = require('intuit-oauth');
const oauthClient = new OAuthClient({
clientId: '<Enter your clientId>',
clientSecret: '<Enter your clientSecret>',
environment: 'sandbox' || 'production',
redirectUri: '<Enter your callback URL>',
});
Options
clientId
- clientID for your app. RequiredclientSecret
- clientSecret fpor your app. Requiredenvironment
- environment for the client. Required
sandbox
- for authorizing in sandbox.production
- for authorizing in production.
redirectUri
- redirectUri on your app to get the authorizationCode
from Intuit Servers. Make sure this redirect URI is also added on your app in the developer portal on the Keys & OAuth tab. Requiredlogging
- by default, logging is disabled i.e false
. To enable providetrue
.
Usage
We assume that you have a basic understanding about OAuth2.0. If not please read
API Documentation
for clear understanding
Authorization Code Flow
The Authorization Code flow is made up of two parts :
Step 1. Redirect user to oauthClient.authorizeUri(options)
.
Step 2. Parse response uri and get access-token using the function
oauthClient.createToken(req.url)
which returns a
Promise.
Step 1
const oauthClient = new OAuthClient({
clientId: '<Enter your clientId>',
clientSecret: '<Enter your clientSecret>',
environment: 'sandbox',
redirectUri: '<http://localhost:8000/callback>',
});
const authUri = oauthClient.authorizeUri({
scope: [OAuthClient.scopes.Accounting, OAuthClient.scopes.OpenId],
state: 'testState',
});
res.redirect(authUri);
Scopes
The available scopes include :
com.intuit.quickbooks.accounting
- for accounting scope include OAuthClient.scopes.Accounting
com.intuit.quickbooks.payment
- for payment scope include OAuthClient.scopes.Payment
com.intuit.quickbooks.payroll
- for QuickBooks Payroll API (whitelisted beta apps only)com.intuit.quickbooks.payroll.timetracking
- for QuickBooks Payroll API for for access to
compensation (whitelisted beta apps only)com.intuit.quickbooks.payroll.benefits
- for QuickBooks Payroll API for access to
benefits/pension/deduction (whitelisted beta apps only)
OpenID Scopes :
openid
- for openID assertion include OAuthClient.scopes.OpenId
profile
- for profile assertion include OAuthClient.scopes.Profile
email
- for email assertion include OAuthClient.scopes.Email
phone
- for phone assertion include OAuthClient.scopes.Phone
address
- for address assertion include OAuthClient.scopes.Address
Step 2
const parseRedirect = req.url;
oauthClient
.createToken(parseRedirect)
.then(function (authResponse) {
console.log('The Token is ' + JSON.stringify(authResponse.json));
})
.catch(function (e) {
console.error('The error message is :' + e.originalMessage);
console.error(e.intuit_tid);
});
Sample
For more clarity, we suggest you take a look at the sample application below :
sample
Helpers
Is AccessToken Valid
You can check if the access_token
associated with the oauthClient
is valid ( not expired ) or
not using the helper method.
if (oauthClient.isAccessTokenValid()) {
console.log('The access_token is valid');
}
if (!oauthClient.isAccessTokenValid()) {
oauthClient
.refresh()
.then(function (authResponse) {
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.json()));
})
.catch(function (e) {
console.error('The error message is :' + e.originalMessage);
console.error(e.intuit_tid);
});
}
** Note: If the access_token is not valid, you can call the client's refresh()
method to refresh
the tokens for you as shown below
Refresh access_token
Access tokens are valid for 3600 seconds (one hour), after which time you need to get a fresh one
using the latest refresh_token returned to you from the previous request. When you request a fresh
access_token, always use the refresh token returned in the most recent token_endpoint response. Your
previous refresh tokens expire 24 hours after you receive a new one.
oauthClient
.refresh()
.then(function (authResponse) {
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.json));
})
.catch(function (e) {
console.error('The error message is :' + e.originalMessage);
console.error(e.intuit_tid);
});
Refresh access_token by passing the refresh_token explicitly
You can call the below helper method to refresh tokens by explictly passing the refresh_token.
**Note : refresh_token
should be of the type string
oauthClient
.refreshUsingToken('<Enter the refresh token>')
.then(function (authResponse) {
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.json));
})
.catch(function (e) {
console.error('The error message is :' + e.originalMessage);
console.error(e.intuit_tid);
});
Revoke access_token
When you no longer need the access_token, you could use the below helper method to revoke the
tokens.
oauthClient
.revoke()
.then(function (authResponse) {
console.log('Tokens revoked : ' + JSON.stringify(authResponse.json));
})
.catch(function (e) {
console.error('The error message is :' + e.originalMessage);
console.error(e.intuit_tid);
});
Alternatively you can also pass access_token
or refresh_token
to this helper method using the
params
object: refer to - Getter / Setter for Token section to know
how to retrieve the token
object
oauthClient
.revoke(params)
.then(function (authResponse) {
console.log('Tokens revoked : ' + JSON.stringify(authResponse.json));
})
.catch(function (e) {
console.error('The error message is :' + e.originalMessage);
console.error(e.intuit_tid);
});
** Note ** : params
is the Token JSON object as shown below : ( If you do not pass the params
then the token object of the client would be considered.)
{
"token_type": "bearer",
"expires_in": 3600,
"refresh_token":"<refresh_token>",
"x_refresh_token_expires_in":15552000,
"access_token":"<access_token>",
"createdAt": "(Optional Default = Date.now()) <Milliseconds> from the unix epoch"
}
** Note ** :
Getter / Setter for Token
You can call the below methods to set and get the tokens using the oauthClient
instance:
Retrieve the Token :
let authToken = oauthClient.getToken().getToken();
`OR`;
let authToken = oauthClient.token.getToken();
Set the Token :
oauthClient.setToken(authToken);
OR;
const oauthClient = new OAuthClient({
clientId: '<Enter your clientId>',
clientSecret: '<Enter your clientSecret>',
environment: 'sandbox',
redirectUri: '<http://localhost:8000/callback>',
token: authToken,
});
The authToken parameters are as follows:
{
token_type: '<String>',
access_token: '<String>',
expires_in: '<Int> Seconds',
refresh_token: '<String>',
x_refresh_token_expires_in: '<Int> Seconds',
id_token: "(Optional Default = '') <String>",
createdAt: '(Optional Default = Date.now()) <Milliseconds> from the unix epoch'
}
Note :
The OAuth Client library converts the accessToken and refreshToken expiry time to TimeStamp
. If
you are setting a stored token, please pass in the createdAt
for accurate experiations.
oauthClient.setToken(authToken);
Migrate OAuth1.0 Tokens to OAuth2.0
You can call the below method to migrate the bearer / refresh tokens from OAuth1.0 to OAuth2.0. You
let params = {
oauth_consumer_key: '<Enter oauth1ConsumerKey>',
oauth_consumer_secret: '<Enter oauth1ConsumerSecret>',
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: Math.round(new Date().getTime() / 1000),
oauth_nonce: 'nonce',
oauth_version: '1.0',
access_token: '<Enter OAuth1.0 access_token>',
access_secret: '<Enter OAuth1.0 access_secret>',
scope: [OAuthClient.scopes.Accounting],
};
oauthClient
.migrate(params)
.then(function (response) {
console.log('The response is ' + JSON.stringify(response));
})
.catch(function (e) {
console.log('The error is ' + e.message);
});
Validate ID Token
You can validate the ID token obtained from Intuit Authorization Server
as shown below :
oauthClient
.validateIdToken()
.then(function (response) {
console.log('Is my ID token validated : ' + response);
})
.catch(function (e) {
console.log('The error is ' + JSON.stringify(e));
});
The client validates the ID Token and returns boolean true
if validates successfully else it would
throw an exception.
Make API Call
You can make API call using the token generated from the client as shown below :
const body = {
TrackQtyOnHand: true,
Name: 'Garden Supplies',
QtyOnHand: 10,
InvStartDate: '2015-01-01',
Type: 'Inventory',
IncomeAccountRef: {
name: 'Sales of Product Income',
value: '79',
},
AssetAccountRef: {
name: 'Inventory Asset',
value: '81',
},
ExpenseAccountRef: {
name: 'Cost of Goods Sold',
value: '80',
},
};
oauthClient
.makeApiCall({
url: 'https://sandbox-quickbooks.api.intuit.com/v3/company/1234/item',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})
.then(function (response) {
console.log('The API response is : ' + response);
})
.catch(function (e) {
console.log('The error is ' + JSON.stringify(e));
});
The client validates the ID Token and returns boolean true
if validates successfully else it would
throw an exception.
Support for PDF format
In order to save the PDF generated from the APIs properly, the correct transport type should be passed into the makeAPI()
.Below is an example of the same:
.makeApiCall({ url: `${url}v3/company/${companyID}/invoice/${invoiceNumber}/pdf?minorversion=59` , headers:{'Content-Type': 'application/pdf','Accept':'application/pdf'}, transport: popsicle.createTransport({type: 'buffer'})})
The response is an actual buffer( binary BLOB) which could then be saved to the file.
Auth-Response
The response provided by the client is a wrapped response of the below items which is what we call
authResponse, lets see how it looks like:
1. response // response from `HTTP Client` used by library
2. token // instance of `Token` Object
3. body // res.body in `text`
4. json // res.body in `JSON`
5. intuit_tid // `intuit-tid` from response headers
A sample AuthResponse
object would look similar to :
{
"token": {
"realmId": "<realmId>",
"token_type": "bearer",
"access_token": "<access_token>",
"refresh_token": "<refresh_token>",
"expires_in": 3600,
"x_refresh_token_expires_in": 8726400,
"id_token": "<id_token>",
"latency": 60000
},
"response": {
"url": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
"headers": {
"content-type": "application/json;charset=UTF-8",
"content-length": "61",
"connection": "close",
"server": "nginx",
"strict-transport-security": "max-age=15552000",
"intuit_tid": "1234-1234-1234-123",
"cache-control": "no-cache, no-store",
"pragma": "no-cache"
},
"body": "{\"id_token\":\"<id_token>\",\"expires_in\":3600,\"token_type\":\"bearer\",\"x_refresh_token_expires_in\":8726400,\"refresh_token\":\"<refresh_token>\",\"access_token\":\"<access_token>\"}",
"status": 200,
"statusText": "OK"
},
"body": "{\"id_token\":\"<id_token>\",\"expires_in\":3600,\"token_type\":\"bearer\",\"x_refresh_token_expires_in\":8726400,\"refresh_token\":\"<refresh_token>\",\"access_token\":\"<access_token>\"}",
"json": {
"access_token": "<access_token>",
"refresh_token": "<refresh_token>",
"token_type": "bearer",
"expires_in": "3600",
"x_refresh_token_expires_in": "8726400",
"id_token": "<id_token>"
},
"intuit_tid": "4245c696-3710-1548-d1e0-d85918e22ebe"
}
You can use the below helper methods to make full use of the Auth Response Object :
oauthClient.createToken(parseRedirect).then(function (authResponse) {
console.log('The Token in JSON is ' + JSON.stringify(authResponse.json));
let status = authResponse.status();
let body = authResponse.text();
let jsonResponse = authResponse.json;
let intuit_tid = authResponse.get_intuit_tid();
});
Error Logging
By default the logging is disabled
i.e set to false
. However, to enable logging, pass
logging=true
when you create the oauthClient
instance :
const oauthClient = new OAuthClient({
clientId: '<Enter your clientId>',
clientSecret: '<Enter your clientSecret>',
environment: 'sandbox',
redirectUri: '<http://localhost:8000/callback>',
logging: true,
});
The logs would be captured under the directory /logs/oAuthClient-log.log
Whenever there is an error, the library throws an exception and you can use the below helper methods
to retrieve more information :
oauthClient.createToken(parseRedirect).catch(function (error) {
console.log(error);
});
FAQ
You can refer to our FAQ if you have any
questions.
Contributing
- You are welcome to send a PR to
develop
branch. - The
master
branch will always point to the latest published version. - The
develop
branch will contain the latest development/testing changes.
Steps
- Fork and clone the repository (
develop
branch). - Run
npm install
for dependencies. - Run
npm test
to execute all specs.
Changelog
See the changelog here
License
Intuit oauth-jsclient
is licensed under the
Apache License, Version 2.0