From 58d4c192468d6b3743db0533bf869cca68b92ad2 Mon Sep 17 00:00:00 2001 From: Brian McCann Date: Wed, 23 Feb 2022 15:38:46 -0500 Subject: [PATCH 1/5] created token saver --- package.json | 1 + sample/TokenSaver.js | 26 ++++++++++++++++++++++++++ sample/app.js | 11 +++++++---- sample/package.json | 3 ++- sample/public/index.html | 13 +------------ sample/runner.js | 18 ++++++++++++++++++ sampleToken.js | 10 ++++++++++ 7 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 sample/TokenSaver.js create mode 100644 sample/runner.js create mode 100644 sampleToken.js diff --git a/package.json b/package.json index 729373d0..8b9dc51c 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "dependencies": { "atob": "2.1.2", "csrf": "^3.0.4", + "dotenv": "^16.0.0", "jsonwebtoken": "^8.3.0", "popsicle": "10.0.1", "query-string": "^6.12.1", diff --git a/sample/TokenSaver.js b/sample/TokenSaver.js new file mode 100644 index 00000000..37356fdb --- /dev/null +++ b/sample/TokenSaver.js @@ -0,0 +1,26 @@ +const {Client} = require('pg') +const {v4: uuidv4} = require('uuid'); + +module.exports = class TokenSaver { + async saveAuthToken(tokenData, yardId) { + console.log('saving auth token') + + const client = new Client() + await client.connect() + + const query = `INSERT INTO erp_tool_credentials + (qb_company_id, qb_access_token, qb_refresh_token, qb_expires_in, + qb_refresh_token_expires_in, qb_created_at, yard_id) + VALUES ($1, $2, $3, $4, $5, to_timestamp($6), $7) RETURNING *` + const values = [tokenData.realmId, tokenData.access_token, tokenData.refresh_token, tokenData.expires_in, tokenData.x_refresh_token_expires_in, tokenData.createdAt/1000, yardId] + + try { + const res = await client.query(query, values) + console.log('saved credentials') + console.log(res.rows[0]) + } catch (err) { + console.log(err.stack) + } + await client.end() + } +} diff --git a/sample/app.js b/sample/app.js index 9c56f73f..355a71e6 100644 --- a/sample/app.js +++ b/sample/app.js @@ -2,6 +2,8 @@ require('dotenv').config(); +console.log(process.env.QB_CLIENT_ID) + /** * Require the dependencies * @type {*|createApplication} @@ -52,14 +54,14 @@ app.get('/', function (req, res) { */ app.get('/authUri', urlencodedParser, function (req, res) { oauthClient = new OAuthClient({ - clientId: req.query.json.clientId, - clientSecret: req.query.json.clientSecret, + clientId: process.env.QB_CLIENT_ID, + clientSecret: process.env.QB_CLIENT_SECRET, environment: req.query.json.environment, - redirectUri: req.query.json.redirectUri, + redirectUri: process.env.REDIRECT_URI, }); const authUri = oauthClient.authorizeUri({ - scope: [OAuthClient.scopes.Accounting], + scope: [OAuthClient.scopes.Accounting, OAuthClient.scopes.Payment], state: 'intuit-test', }); res.send(authUri); @@ -72,6 +74,7 @@ app.get('/callback', function (req, res) { oauthClient .createToken(req.url) .then(function (authResponse) { + console.log("auth response: *** \n", authResponse.token) oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2); }) .catch(function (e) { diff --git a/sample/package.json b/sample/package.json index 0c00146e..9f3d7ad2 100644 --- a/sample/package.json +++ b/sample/package.json @@ -19,7 +19,8 @@ "express-session": "^1.14.2", "intuit-oauth": "^3.0.1", "ngrok": "^3.2.5", - "path": "^0.12.7" + "path": "^0.12.7", + "pg": "^8.7.3" }, "devDependencies": { "snyk": "^1.316.1" diff --git a/sample/public/index.html b/sample/public/index.html index 2006254e..893f9b4b 100644 --- a/sample/public/index.html +++ b/sample/public/index.html @@ -26,14 +26,6 @@

intuit-nodejsclient sample application

OAuth2.0

( Please enter the client credentials below )


-
- - -
-
- - -
-
- -
-
+

Now click the Connect to QuickBooks button below.


diff --git a/sample/runner.js b/sample/runner.js
new file mode 100644
index 00000000..9dd62b5c
--- /dev/null
+++ b/sample/runner.js
@@ -0,0 +1,18 @@
+
+require('dotenv').config()
+
+const TokenSaver = require('./TokenSaver');
+
+const saver = new TokenSaver();
+
+const tokenData = {
+    realmId: '4625319964620848278',
+    token_type: 'bearer',
+    access_token: 'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..wLdClMRLM6QjRLArR-CqqA.898qnGtVO5c3w6ylZv19zhvAJPOhr-hW-jjToIK2OxMz18CrJ1HCKdDAWuYQfb6dBd1-ObG8mw2Xi8SeRes8GDcNWG-tKbkVe9c15WE6BHwH_3JK3i2OW1ZIDLCA0raBg5YYcdhZEUyJCXMXhmzWtEWDPOUk69fd1lX4W0TMzdI5LlZ2UQ5AsNSQO2oeqNCa5_g6oMnJtts2nRS5FEb7Tk_Rjo0IB9LyJdqz_J4HjBSuuXCBUMgwMnwlHRiQTm0iZzjErsED4A8YaFjf5IqTK3xMO-n_1e-FDg_SC3Mr_AStGyQvAIGBYYds5MZ8m0MeRqKHECzdeo2hRfa9Mdy1B6Vew-xvTNTMjnjyREz_5pkJKGDCrWfISRF5kn8NC2eVWp1zgrmC2K1I8ugiFpcENzfO3KyMyFpnDyjwzRmjDBGUBBqtdBdt12hG34RzOQ-jde17q5YHrH6D4ObhSzALfZbKIlhr2b8z46NWI2x36KZKeu9uhjpvpxksOQ05XvQOvNG72LOxYrfuTQ-gRrk8-lPHArwsXS09L6xBKqc1F2dD2ucrM2CrdsdoHuejrMNKQ3N1JDyiPOYbw6IlDO6qlDLAMV-jKMBb1Pgcq_G6qGOg4EdWVOJjzd4Kf1YA6azhGp4RefibuNJKxWn7cskh2FkSGSBJlPqrPDdsj0vtp_Ueolh80dXjYMrVSQGFBzmq5eUNQVaEMvxagVQRWDD26RlPNZXunCoMnvKJNUAnctnCF5idTJadgJeaoNtfH_xE.kY9waBRHrpiK3HlD6ShydQ',
+    refresh_token: 'AB11654363506sQAc20kr5ZARdEG0urk1IkoXIgZUx5b6F6sk0',
+    expires_in: 3600,
+    x_refresh_token_expires_in: 8726400,
+    createdAt: 1645637106335
+}
+
+saver.saveAuthToken(tokenData, '00000000-0000-0000-0000-000000000000')
diff --git a/sampleToken.js b/sampleToken.js
new file mode 100644
index 00000000..7f90c6eb
--- /dev/null
+++ b/sampleToken.js
@@ -0,0 +1,10 @@
+// eslint-disable-next-line strict
+const data = {
+    realmId: '4625319964620848278',
+    token_type: 'bearer',
+    access_token: 'eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiZGlyIn0..wLdClMRLM6QjRLArR-CqqA.898qnGtVO5c3w6ylZv19zhvAJPOhr-hW-jjToIK2OxMz18CrJ1HCKdDAWuYQfb6dBd1-ObG8mw2Xi8SeRes8GDcNWG-tKbkVe9c15WE6BHwH_3JK3i2OW1ZIDLCA0raBg5YYcdhZEUyJCXMXhmzWtEWDPOUk69fd1lX4W0TMzdI5LlZ2UQ5AsNSQO2oeqNCa5_g6oMnJtts2nRS5FEb7Tk_Rjo0IB9LyJdqz_J4HjBSuuXCBUMgwMnwlHRiQTm0iZzjErsED4A8YaFjf5IqTK3xMO-n_1e-FDg_SC3Mr_AStGyQvAIGBYYds5MZ8m0MeRqKHECzdeo2hRfa9Mdy1B6Vew-xvTNTMjnjyREz_5pkJKGDCrWfISRF5kn8NC2eVWp1zgrmC2K1I8ugiFpcENzfO3KyMyFpnDyjwzRmjDBGUBBqtdBdt12hG34RzOQ-jde17q5YHrH6D4ObhSzALfZbKIlhr2b8z46NWI2x36KZKeu9uhjpvpxksOQ05XvQOvNG72LOxYrfuTQ-gRrk8-lPHArwsXS09L6xBKqc1F2dD2ucrM2CrdsdoHuejrMNKQ3N1JDyiPOYbw6IlDO6qlDLAMV-jKMBb1Pgcq_G6qGOg4EdWVOJjzd4Kf1YA6azhGp4RefibuNJKxWn7cskh2FkSGSBJlPqrPDdsj0vtp_Ueolh80dXjYMrVSQGFBzmq5eUNQVaEMvxagVQRWDD26RlPNZXunCoMnvKJNUAnctnCF5idTJadgJeaoNtfH_xE.kY9waBRHrpiK3HlD6ShydQ',
+    refresh_token: 'AB11654363506sQAc20kr5ZARdEG0urk1IkoXIgZUx5b6F6sk0',
+    expires_in: 3600,
+    x_refresh_token_expires_in: 8726400,
+    createdAt: 1645637106335,
+}

From dc16996487a167a6bcaa41dd876f2b4720fce234 Mon Sep 17 00:00:00 2001
From: Brian McCann 
Date: Thu, 24 Feb 2022 06:22:59 -0500
Subject: [PATCH 2/5] using saveAuthToken fn to save returned response

setting yard ID as variable in the server so it can be saved with creds
---
 sample/app.js            | 209 +++++++++++++++++++++------------------
 sample/public/index.html |  93 +++++++++--------
 sample/runner.js         |  26 +++--
 3 files changed, 181 insertions(+), 147 deletions(-)

diff --git a/sample/app.js b/sample/app.js
index 355a71e6..3a78b21b 100644
--- a/sample/app.js
+++ b/sample/app.js
@@ -2,31 +2,32 @@
 
 require('dotenv').config();
 
-console.log(process.env.QB_CLIENT_ID)
-
 /**
  * Require the dependencies
  * @type {*|createApplication}
  */
 const express = require('express');
+const TokenSaver = require('./TokenSaver')
 
 const app = express();
 const path = require('path');
 const OAuthClient = require('intuit-oauth');
 const bodyParser = require('body-parser');
 const ngrok = process.env.NGROK_ENABLED === 'true' ? require('ngrok') : null;
+const querystring = require("querystring");
+const tokenSaver = new TokenSaver()
 
 /**
  * Configure View and Handlebars
  */
-app.use(bodyParser.urlencoded({ extended: true }));
+app.use(bodyParser.urlencoded({extended: true}));
 app.use(express.static(path.join(__dirname, '/public')));
 app.engine('html', require('ejs').renderFile);
 
 app.set('view engine', 'html');
 app.use(bodyParser.json());
 
-const urlencodedParser = bodyParser.urlencoded({ extended: false });
+const urlencodedParser = bodyParser.urlencoded({extended: false});
 
 /**
  * App Variables
@@ -41,152 +42,164 @@ let redirectUri = '';
  */
 
 let oauthClient = null;
+let yardId = null;
 
 /**
  * Home Route
  */
 app.get('/', function (req, res) {
-  res.render('index');
+    res.render('index');
 });
 
 /**
  * Get the AuthorizeUri
  */
 app.get('/authUri', urlencodedParser, function (req, res) {
-  oauthClient = new OAuthClient({
-    clientId: process.env.QB_CLIENT_ID,
-    clientSecret: process.env.QB_CLIENT_SECRET,
-    environment: req.query.json.environment,
-    redirectUri: process.env.REDIRECT_URI,
-  });
-
-  const authUri = oauthClient.authorizeUri({
-    scope: [OAuthClient.scopes.Accounting, OAuthClient.scopes.Payment],
-    state: 'intuit-test',
-  });
-  res.send(authUri);
+
+
+    yardId = req.query.json.yardId
+    console.log('yardId is ', yardId)
+
+    oauthClient = new OAuthClient({
+        clientId: process.env.QB_CLIENT_ID,
+        clientSecret: process.env.QB_CLIENT_SECRET,
+        environment: req.query.json.environment,
+        redirectUri: process.env.REDIRECT_URI,
+    });
+
+    const authUri = oauthClient.authorizeUri({
+        scope: [OAuthClient.scopes.Accounting, OAuthClient.scopes.Payment],
+        state: 'intuit-test',
+    });
+    res.send(authUri);
 });
 
 /**
  * Handle the callback to extract the `Auth Code` and exchange them for `Bearer-Tokens`
  */
 app.get('/callback', function (req, res) {
-  oauthClient
-    .createToken(req.url)
-    .then(function (authResponse) {
-        console.log("auth response: *** \n", authResponse.token)
-      oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2);
-    })
-    .catch(function (e) {
-      console.error(e);
-    });
 
-  res.send('');
+    const parsedUrl = querystring.parse(req.url)
+    oauthClient
+        .createToken(req.url)
+        .then(function (authResponse) {
+            console.log("got auth response")
+            oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2);
+            return authResponse
+        })
+        .then(function (authResponse) {
+            return tokenSaver.saveAuthToken(authResponse.token, yardId)
+        })
+        .catch(function (e) {
+            console.error(e);
+        });
+
+    res.send('');
 });
 
 /**
  * Display the token : CAUTION : JUST for sample purposes
  */
 app.get('/retrieveToken', function (req, res) {
-  res.send(oauth2_token_json);
+    res.send(oauth2_token_json);
 });
 
 /**
  * Refresh the access-token
  */
 app.get('/refreshAccessToken', function (req, res) {
-  oauthClient
-    .refresh()
-    .then(function (authResponse) {
-      console.log(`The Refresh Token is  ${JSON.stringify(authResponse.getJson())}`);
-      oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2);
-      res.send(oauth2_token_json);
-    })
-    .catch(function (e) {
-      console.error(e);
-    });
+    oauthClient
+        .refresh()
+        .then(function (authResponse) {
+            console.log(`The Refresh Token is  ${JSON.stringify(authResponse.getJson())}`);
+            oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2);
+            res.send(oauth2_token_json);
+        })
+        .catch(function (e) {
+            console.error(e);
+        });
 });
 
 /**
  * getCompanyInfo ()
  */
 app.get('/getCompanyInfo', function (req, res) {
-  const companyID = oauthClient.getToken().realmId;
-
-  const url =
-    oauthClient.environment == 'sandbox'
-      ? OAuthClient.environment.sandbox
-      : OAuthClient.environment.production;
-
-  oauthClient
-    .makeApiCall({ url: `${url}v3/company/${companyID}/companyinfo/${companyID}` })
-    .then(function (authResponse) {
-      console.log(`The response for API call is :${JSON.stringify(authResponse)}`);
-      res.send(JSON.parse(authResponse.text()));
-    })
-    .catch(function (e) {
-      console.error(e);
-    });
+    const companyID = oauthClient.getToken().realmId;
+
+    const url =
+        oauthClient.environment == 'sandbox'
+            ? OAuthClient.environment.sandbox
+            : OAuthClient.environment.production;
+
+    oauthClient
+        .makeApiCall({url: `${url}v3/company/${companyID}/companyinfo/${companyID}`})
+        .then(function (authResponse) {
+            console.log(`The response for API call is :${JSON.stringify(authResponse)}`);
+            res.send(JSON.parse(authResponse.text()));
+        })
+        .catch(function (e) {
+            console.error(e);
+        });
 });
 
 /**
  * disconnect ()
  */
 app.get('/disconnect', function (req, res) {
-  console.log('The disconnect called ');
-  const authUri = oauthClient.authorizeUri({
-    scope: [OAuthClient.scopes.OpenId, OAuthClient.scopes.Email],
-    state: 'intuit-test',
-  });
-  res.redirect(authUri);
+    console.log('The disconnect called ');
+    const authUri = oauthClient.authorizeUri({
+        scope: [OAuthClient.scopes.OpenId, OAuthClient.scopes.Email],
+        state: 'intuit-test',
+    });
+    res.redirect(authUri);
 });
 
 /**
  * Start server on HTTP (will use ngrok for HTTPS forwarding)
  */
 const server = app.listen(process.env.PORT || 8000, () => {
-  console.log(`💻 Server listening on port ${server.address().port}`);
-  if (!ngrok) {
-    redirectUri = `${server.address().port}` + '/callback';
-    console.log(
-      `💳  Step 1 : Paste this URL in your browser : ` +
-        'http://localhost:' +
-        `${server.address().port}`,
-    );
-    console.log(
-      '💳  Step 2 : Copy and Paste the clientId and clientSecret from : https://developer.intuit.com',
-    );
-    console.log(
-      `💳  Step 3 : Copy Paste this callback URL into redirectURI :` +
-        'http://localhost:' +
-        `${server.address().port}` +
-        '/callback',
-    );
-    console.log(
-      `💻  Step 4 : Make Sure this redirect URI is also listed under the Redirect URIs on your app in : https://developer.intuit.com`,
-    );
-  }
+    console.log(`💻 Server listening on port ${server.address().port}`);
+    if (!ngrok) {
+        redirectUri = `${server.address().port}` + '/callback';
+        console.log(
+            `💳  Step 1 : Paste this URL in your browser : ` +
+            'http://localhost:' +
+            `${server.address().port}`,
+        );
+        console.log(
+            '💳  Step 2 : Copy and Paste the clientId and clientSecret from : https://developer.intuit.com',
+        );
+        console.log(
+            `💳  Step 3 : Copy Paste this callback URL into redirectURI :` +
+            'http://localhost:' +
+            `${server.address().port}` +
+            '/callback',
+        );
+        console.log(
+            `💻  Step 4 : Make Sure this redirect URI is also listed under the Redirect URIs on your app in : https://developer.intuit.com`,
+        );
+    }
 });
 
 /**
  * Optional : If NGROK is enabled
  */
 if (ngrok) {
-  console.log('NGROK Enabled');
-  ngrok
-    .connect({ addr: process.env.PORT || 8000 })
-    .then((url) => {
-      redirectUri = `${url}/callback`;
-      console.log(`💳 Step 1 : Paste this URL in your browser :  ${url}`);
-      console.log(
-        '💳 Step 2 : Copy and Paste the clientId and clientSecret from : https://developer.intuit.com',
-      );
-      console.log(`💳 Step 3 : Copy Paste this callback URL into redirectURI :  ${redirectUri}`);
-      console.log(
-        `💻 Step 4 : Make Sure this redirect URI is also listed under the Redirect URIs on your app in : https://developer.intuit.com`,
-      );
-    })
-    .catch(() => {
-      process.exit(1);
-    });
+    console.log('NGROK Enabled');
+    ngrok
+        .connect({addr: process.env.PORT || 8000})
+        .then((url) => {
+            redirectUri = `${url}/callback`;
+            console.log(`💳 Step 1 : Paste this URL in your browser :  ${url}`);
+            console.log(
+                '💳 Step 2 : Copy and Paste the clientId and clientSecret from : https://developer.intuit.com',
+            );
+            console.log(`💳 Step 3 : Copy Paste this callback URL into redirectURI :  ${redirectUri}`);
+            console.log(
+                `💻 Step 4 : Make Sure this redirect URI is also listed under the Redirect URIs on your app in : https://developer.intuit.com`,
+            );
+        })
+        .catch(() => {
+            process.exit(1);
+        });
 }
diff --git a/sample/public/index.html b/sample/public/index.html
index 893f9b4b..90b1b2e4 100644
--- a/sample/public/index.html
+++ b/sample/public/index.html
@@ -1,7 +1,8 @@
 
 
 
-    
+    
     
     
     
@@ -26,81 +27,95 @@ 

intuit-nodejsclient sample application

OAuth2.0

( Please enter the client credentials below )


+
+ + +

Now click the Connect to QuickBooks button below.


-    
-    
-    
-    
- -

Make an API call

( Please refer to our API Explorer )

-

If there is no access token or the access token is invalid, click either the Connect to QucikBooks or Sign with Intuit button above.

+ + + +
+ +

Make an API call

( Please refer to our API + Explorer )

+

If there is no access token or the access token is invalid, click either the Connect to QucikBooks or Sign + with Intuit button above.


-    
+    
 
-    
+

More info:


- © 2018 Intuit™, Inc. All rights reserved. Intuit and QuickBooks are registered trademarks of Intuit Inc. + © 2018 Intuit™, Inc. All rights reserved. Intuit and QuickBooks are registered trademarks of Intuit + Inc.