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..c7ce9d3a --- /dev/null +++ b/sample/TokenSaver.js @@ -0,0 +1,39 @@ +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 + (erp_system_id, qb_access_token, qb_refresh_token, qb_expires_in, + qb_refresh_token_expires_in, created_at, yard_id) + VALUES ($1, $2, $3, $4, $5, to_timestamp($6), $7) + ON CONFLICT + ON CONSTRAINT erp_tool_credentials_pkey + DO UPDATE + SET erp_system_id = $1, + qb_access_token = $2, + qb_refresh_token = $3, + qb_expires_in = $4, + qb_refresh_token_expires_in = $5, + created_at = to_timestamp($6), + yard_id = $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..5f0326d9 100644 --- a/sample/app.js +++ b/sample/app.js @@ -7,24 +7,27 @@ require('dotenv').config(); * @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 @@ -39,151 +42,167 @@ 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: req.query.json.clientId, - clientSecret: req.query.json.clientSecret, - environment: req.query.json.environment, - redirectUri: req.query.json.redirectUri, - }); - - const authUri = oauthClient.authorizeUri({ - scope: [OAuthClient.scopes.Accounting], - state: 'intuit-test', - }); - res.send(authUri); + + yardId = req.query.json.yardId + console.log('yardId is ', yardId) + + //? configure the client with our app creds + 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', + }); + //? send the auth URI back to the client + 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) { - oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2); - }) - .catch(function (e) { - console.error(e); - }); - - res.send(''); + oauthClient + .createToken(req.url) + .then(function (authResponse) { + console.log("got auth response. raw QB token is: \n") + console.log(JSON.stringify(authResponse.token)) + console.log('-------') + console.log('-------') + oauth2_token_json = JSON.stringify(authResponse.getJson(), null, 2); + return authResponse + }) + .then(function (authResponse) { + //? save the returned token to the DB + 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/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..832f3241 100644 --- a/sample/public/index.html +++ b/sample/public/index.html @@ -1,7 +1,8 @@ - + @@ -27,91 +28,93 @@

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.