Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[![SDK Banner](views/SDK.png)][ss1]


[![Build Status](https://travis-ci.org/intuit/oauth-jsclient.svg?branch=master)](https://travis-ci.org/intuit/oauth-jsclient)
[![Build Status](https://travis-ci.org/intuit/oauth-jsclient.svg?branch=develop)](https://travis-ci.org/intuit/oauth-jsclient?branch=develop)
[![NPM Package Version](https://img.shields.io/npm/v/intuit-oauth.svg?style=flat-square)](https://www.npmjs.com/package/intuit-oauth)
[![Coverage Status](https://coveralls.io/repos/github/intuit/oauth-jsclient/badge.svg)](https://coveralls.io/github/intuit/oauth-jsclient)
[![Coverage Status](https://coveralls.io/repos/github/intuit/oauth-jsclient/badge.svg?branch=develop)](https://coveralls.io/github/intuit/oauth-jsclient?branch=develop)
[![Known Vulnerabilities](https://snyk.io/test/github/intuit/oauth-jsclient/badge.svg)](https://snyk.io/test/github/intuit/oauth-jsclient)


Expand Down Expand Up @@ -129,7 +129,7 @@ The available scopes include :

OpenID Scopes :

* `openid` - for openID assertion include `OAuthClient.scopes.Openid`
* `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`
Expand Down Expand Up @@ -197,7 +197,7 @@ Access tokens are valid for 3600 seconds (one hour), after which time you need t

oauthClient.refresh()
.then(function(authResponse) {
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.json()));
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.getJson()));
})
.catch(function(e) {
console.error("The error message is :"+e.originalMessage);
Expand All @@ -214,7 +214,7 @@ You can call the below helper method to refresh tokens by explictly passing the

oauthClient.refreshUsingToken('<Enter the refresh token>')
.then(function(authResponse) {
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.json()));
console.log('Tokens refreshed : ' + JSON.stringify(authResponse.getJson()));
})
.catch(function(e) {
console.error("The error message is :"+e.originalMessage);
Expand All @@ -231,7 +231,7 @@ When you no longer need the access_token, you could use the below helper method

oauthClient.revoke()
.then(function(authResponse) {
console.log('Tokens revoked : ' + JSON.stringify(authResponse.json()));
console.log('Tokens revoked : ' + JSON.stringify(authResponse.getJson()));
})
.catch(function(e) {
console.error("The error message is :"+e.originalMessage);
Expand All @@ -244,7 +244,7 @@ Alternatively you can also pass `access_token` or `refresh_token` to this helper

oauthClient.revoke(params)
.then(function(authResponse) {
console.log('Tokens revoked : ' + JSON.stringify(authResponse.json()));
console.log('Tokens revoked : ' + JSON.stringify(authResponse.getJson()));
})
.catch(function(e) {
console.error("The error message is :"+e.originalMessage);
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "intuit-oauth",
"version": "2.0.0",
"version": "2.0.1",
"description": "Intuit Node.js client for OAuth2.0 and OpenIDConnect",
"main": "./src/OAuthClient.js",
"scripts": {
Expand Down Expand Up @@ -68,8 +68,8 @@
},
"homepage": "https://github.com/intuit/oauth-jsclient",
"dependencies": {
"csrf": "^3.0.4",
"atob": "2.1.2",
"csrf": "^3.0.4",
"es6-promise": "^4.2.5",
"events": "^3.0.0",
"idtoken-verifier": "^1.2.0",
Expand All @@ -83,6 +83,7 @@
},
"devDependencies": {
"body-parser": "^1.15.2",
"btoa": "^1.2.1",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chance": "^1.1.3",
Expand Down
7 changes: 3 additions & 4 deletions src/OAuthClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ OAuthClient.prototype.validateIdToken = function validateIdToken(params = {}) {
// Step 1 : First check if the issuer is as mentioned in "issuer"
if (id_token_payload.iss !== 'https://oauth.platform.intuit.com/op/v1') return false;

// Step 2 : check if the aud field in idToken is same as application's clientId
if (id_token_payload.aud !== this.clientId) return false;
// Step 2 : check if the aud field in idToken contains application's clientId
if (!id_token_payload.aud.find(audience => (audience === this.clientId))) return false;

// Step 3 : ensure the timestamp has not elapsed
if (id_token_payload.exp < Date.now() / 1000) return false;
Expand Down Expand Up @@ -507,8 +507,7 @@ OAuthClient.prototype.getKeyFromJWKsURI = function getKeyFromJWKsURI(id_token, k
return (new Promise(((resolve) => {
resolve(this.loadResponse(request));
}))).then((response) => {
if (response.status !== '200') throw new Error('Could not reach JWK endpoint');

if (Number(response.status) !== 200) throw new Error('Could not reach JWK endpoint');
// Find the key by KID
const responseBody = JSON.parse(response.body);
const key = responseBody.keys.find(el => (el.kid === kid));
Expand Down
55 changes: 45 additions & 10 deletions test/OAuthClientTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const nock = require('nock');
const sinon = require('sinon');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const btoa = require('btoa');
const jwt = require('jsonwebtoken');

// eslint-disable-next-line no-unused-vars
const getPem = require('rsa-pem-from-mod-exp');
Expand All @@ -23,11 +25,14 @@ const expectedTokenResponse = require('./mocks/tokenResponse.json');
const expectedUserInfo = require('./mocks/userInfo.json');
const expectedMakeAPICall = require('./mocks/makeAPICallResponse.json');
const expectedjwkResponseCall = require('./mocks/jwkResponse.json');
const expectedvalidateIdToken = require('./mocks/validateIdToken.json');
const expectedOpenIDToken = require('./mocks/openID-token.json');
// var expectedErrorResponse = require('./mocks/errorResponse.json');
const expectedMigrationResponse = require('./mocks/authResponse.json');

require.cache[require.resolve('rsa-pem-from-mod-exp')] = {
exports: sinon.stub().returns(3),
};

const oauthClient = new OAuthClientTest({
clientId: 'clientID',
clientSecret: 'clientSecret',
Expand Down Expand Up @@ -262,7 +267,7 @@ describe('Tests for OAuthClient', () => {
});

// make API Call
describe('Make API Call ', () => {
describe('Make API Call', () => {
before(() => {
nock('https://sandbox-quickbooks.api.intuit.com').persist()
.get('/v3/company/12345/companyinfo/12345')
Expand All @@ -285,6 +290,20 @@ describe('Tests for OAuthClient', () => {
.to.be.equal(JSON.stringify(expectedMakeAPICall));
});
});
it('Make API Call in Sandbox Environment with headers as parameters', () => {
oauthClient.getToken().realmId = '12345';
// eslint-disable-next-line no-useless-concat
return oauthClient.makeApiCall({
url: 'https://sandbox-quickbooks.api.intuit.com/v3/company/' + '12345' + '/companyinfo/' + '12345',
headers: {
Accept: "application/json",
}
})
.then((authResponse) => {
expect(JSON.stringify(authResponse.getJson()))
.to.be.equal(JSON.stringify(expectedMakeAPICall));
});
});
it('loadResponseFromJWKsURI', () => {
const request = {
url: 'https://sandbox-quickbooks.api.intuit.com/v3/company/12345/companyinfo/12345',
Expand Down Expand Up @@ -324,9 +343,6 @@ describe('Tests for OAuthClient', () => {
});

describe('getPublicKey', () => {
require.cache[require.resolve('rsa-pem-from-mod-exp')] = {
exports: sinon.mock().returns(3),
};
const pem = oauthClient.getPublicKey(3, 4);
expect(pem).to.be.equal(3);
});
Expand Down Expand Up @@ -359,7 +375,7 @@ describe('Validate Id Token ', () => {
before(() => {
nock('https://oauth.platform.intuit.com').persist()
.get('/op/v1/jwks')
.reply(200, expectedjwkResponseCall, {
.reply(200, expectedjwkResponseCall.body, {
'content-type': 'application/json;charset=UTF-8',
'content-length': '264',
connection: 'close',
Expand All @@ -369,26 +385,41 @@ describe('Validate Id Token ', () => {
'cache-control': 'no-cache, no-store',
pragma: 'no-cache',
});
sinon.stub(jwt, 'verify').returns(true);
});

const mockIdTokenPayload = {
sub: 'b053d994-07d5-468d-b7ee-22e349d2e739',
aud: ['clientID'],
realmid: '1108033471',
auth_time: 1462554475,
iss: 'https://oauth.platform.intuit.com/op/v1',
exp: Date.now() + 60000,
iat: 1462557728,
};

const tokenParts = expectedOpenIDToken.id_token.split('.');
const encodedMockIdTokenPayload = tokenParts[0].concat('.', btoa(JSON.stringify(mockIdTokenPayload)));
const mockToken = Object.assign({}, expectedOpenIDToken, { id_token: encodedMockIdTokenPayload });

it('validate id token returns error if id_token missing', async () => {
delete oauthClient.getToken().id_token;
await expect(oauthClient.validateIdToken()).to.be.rejectedWith(Error);
});

it('Validate Id Token', () => {
oauthClient.getToken().setToken(expectedOpenIDToken);
oauthClient.getToken().setToken(mockToken);
oauthClient.validateIdToken()
.then((response) => {
expect(response).to.be.equal(expectedvalidateIdToken);
expect(response).to.be.equal(true);
});
});

it('Validate Id Token alternative', () => {
oauthClient.setToken(expectedOpenIDToken);
oauthClient.setToken(mockToken);
oauthClient.validateIdToken()
.then((response) => {
expect(response).to.be.equal(expectedOpenIDToken);
expect(response).to.be.equal(true);
});
});
});
Expand Down Expand Up @@ -474,6 +505,10 @@ describe('Generate OAuth1Sign', () => {

const oauth1Sign = oauthClient.generateOauth1Sign(params);
expect(oauth1Sign).to.be.a('String');
expect(oauth1Sign).to.have.string('oauth_consumer_key="qyprdFsHNQtdRupMKmYnDt6MOjWBW9');
expect(oauth1Sign).to.have.string('oauth_nonce="nonce');
expect(oauth1Sign).to.have.string('oauth_version="1.0');
expect(oauth1Sign).to.have.string('oauth_token', 'oauth_timestamp', 'oauth_signature');
});
});

Expand Down
4 changes: 2 additions & 2 deletions test/mocks/jwkResponse.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"body":"{\"keys\": [{\"kty\":\"sample_value_kty\",\"e\":\"sample_value_e\",\"use\":\"sample_value_use\",\"kid\":\"sample_value_kid\",\"alg\":\"sample_value_alg\",\"n\":\"sample_value_n\"}]}"
}
"body":"{\"keys\": [{\"kty\":\"sample_value_kty\",\"e\":\"sample_value_e\",\"use\":\"sample_value_use\",\"kid\":\"r4p5SbL2qaFehFzhj8gI\",\"alg\":\"sample_value_alg\",\"n\":\"sample_value_n\"}]}"
}