Socket
Socket
Sign inDemoInstall

@ndustrial/contxt-sdk

Package Overview
Dependencies
Maintainers
9
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ndustrial/contxt-sdk - npm Package Compare versions

Comparing version 0.0.14 to 0.0.15

14

CHANGELOG.md

@@ -0,1 +1,7 @@

## [v0.0.15](http://github.com/ndustrialio/contxt-sdk-js/tree/v0.0.15) (2018-06-21)
**Changed**
* Auth0WebAuth now automatically handles refreshing Access and API tokens instead of forcing the user to log in again every two hours.
## [v0.0.14](http://github.com/ndustrialio/contxt-sdk-js/tree/v0.0.14) (2018-06-18)

@@ -10,9 +16,11 @@

* Adds the ability to set up custom axios interceptors to be used on each request and response made to an API. (More information available at at {@link https://github.com/axios/axios#interceptors axios Interceptors})
**Added**
* The ability to set up custom axios interceptors to be used on each request and response made to an API. (More information available at at {@link https://github.com/axios/axios#interceptors axios Interceptors})
## [v0.0.12](http://github.com/ndustrialio/contxt-sdk-js/tree/v0.0.12) (2018-06-14)
**Changed**
**Added**
* Added methods around the display and manipulation of Cost Centers. They are namespaced under facilities (i.e. `facilities.costCenters.methodName()`) and include:
* Methods around the display and manipulation of Cost Centers. They are namespaced under facilities (i.e. `facilities.costCenters.methodName()`) and include:
* CostCenters#addFacility to add a facility to a cost center

@@ -19,0 +27,0 @@ * CostCenters#create for creating a new cost center

@@ -12,2 +12,9 @@ <a name="Auth0WebAuth"></a>

This SessionType is set up to refresh auth tokens automatically. To ensure this works, make sure
your single page application has [Cross-Origin Authentication](https://auth0.com/docs/cross-origin-authentication#configure-your-application-for-cross-origin-authentication)
enabled in Auth0.
*NOTE*: The web origin added in auth0 should be something like
"http://localhost:5000", not "http://localhost:5000/callback"
**Kind**: global class

@@ -102,4 +109,5 @@

### contxtSdk.auth.logOut()
Logs the user out by removing any stored session info and redirecting to the root
Logs the user out by removing any stored session info, clearing any token renewal, and
redirecting to the root
**Kind**: instance method of [<code>Auth0WebAuth</code>](#Auth0WebAuth)

@@ -12,2 +12,7 @@ ## Classes

default is <code>/callback</code>).</p>
<p>This SessionType is set up to refresh auth tokens automatically. To ensure this works, make sure
your single page application has <a href="https://auth0.com/docs/cross-origin-authentication#configure-your-application-for-cross-origin-authentication">Cross-Origin Authentication</a>
enabled in Auth0.</p>
<p><em>NOTE</em>: The web origin added in auth0 should be something like
&quot;<a href="http://localhost:5000&quot;">http://localhost:5000&quot;</a>, not &quot;<a href="http://localhost:5000/callback&quot;">http://localhost:5000/callback&quot;</a></p>
</dd>

@@ -14,0 +19,0 @@ <dt><a href="./Config.md">Config</a></dt>

@@ -1405,2 +1405,6 @@ import axios from 'axios';

});
if (this.isAuthenticated()) {
this._scheduleTokenRenewal();
}
}

@@ -1449,18 +1453,3 @@

return this._parseWebAuthHash().then(function (hash) {
return Promise.all([{
accessToken: hash.accessToken,
expiresAt: hash.expiresIn * 1000 + Date.now()
}, _this2._getApiToken(hash.accessToken)]);
}).then(function (_ref) {
var _ref2 = slicedToArray(_ref, 2),
partialSessionInfo = _ref2[0],
apiToken = _ref2[1];
var sessionInfo = _extends({}, partialSessionInfo, {
apiToken: apiToken
});
_this2._saveSession(sessionInfo);
return sessionInfo;
return _this2._handleNewSessionInfo(hash);
}).then(function (sessionInfo) {

@@ -1486,3 +1475,3 @@ var redirectPathname = _this2._getRedirectPathname();

return hasTokens && this._sessionInfo.expiresAt > Date.now();
return hasTokens;
}

@@ -1505,2 +1494,4 @@

clearTimeout(this._tokenRenewalTimeout);
this._onRedirect('/');

@@ -1510,2 +1501,20 @@ }

}, {
key: '_checkSession',
value: function _checkSession() {
var _this3 = this;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return new Promise(function (resolve, reject) {
_this3._auth0.checkSession(options, function (err, response) {
if (err || !response) {
return reject(err || new Error('No valid tokens returned from auth0'));
}
return resolve(response);
});
});
}
}, {
key: '_defaultOnRedirect',

@@ -1519,9 +1528,9 @@ value: function _defaultOnRedirect(pathname) {

value: function _getApiToken(accessToken) {
var _this3 = this;
var _this4 = this;
return axios.post(this._sdk.config.audiences.contxtAuth.host + '/v1/token', {
audiences: Object.keys(this._sdk.config.audiences).map(function (audienceName) {
return _this3._sdk.config.audiences[audienceName].clientId;
return _this4._sdk.config.audiences[audienceName].clientId;
}).filter(function (clientId) {
return clientId !== _this3._sdk.config.audiences.contxtAuth.clientId;
return clientId !== _this4._sdk.config.audiences.contxtAuth.clientId;
}),

@@ -1531,4 +1540,4 @@ nonce: 'nonce'

headers: { Authorization: 'Bearer ' + accessToken }
}).then(function (_ref3) {
var data = _ref3.data;
}).then(function (_ref) {
var data = _ref.data;
return data.access_token;

@@ -1541,12 +1550,17 @@ });

value: function _getCurrentTokenByType(type) {
var _this4 = this;
var propertyName = type + 'Token';
var tokenExpiresAtBufferMs = this._sdk.config.auth.tokenExpiresAtBufferMs || 0;
var bufferedExpiresAt = this._sessionInfo.expiresAt - tokenExpiresAtBufferMs;
var needsNewToken = Date.now() > bufferedExpiresAt;
return new Promise(function (resolve, reject) {
var propertyName = type + 'Token';
if (!needsNewToken && this._sessionInfo[propertyName]) {
return Promise.resolve(this._sessionInfo[propertyName]);
}
if (!(_this4._sessionInfo && _this4._sessionInfo[propertyName])) {
reject(new Error('No ' + type + ' token found'));
return this._getUpdatedSessionInfo().then(function (sessionInfo) {
if (!sessionInfo[propertyName]) {
throw new Error('No ' + type + ' token found');
}
resolve(_this4._sessionInfo[propertyName]);
return sessionInfo[propertyName];
});

@@ -1565,2 +1579,50 @@ }

}, {
key: '_getUpdatedSessionInfo',
value: function _getUpdatedSessionInfo() {
var _this5 = this;
if (!this._updatedSessionInfoPromise) {
this._updatedSessionInfoPromise = this._checkSession().then(function (sessionInfo) {
return _this5._handleNewSessionInfo(sessionInfo);
}).then(function (sessionInfo) {
_this5._updatedSessionInfoPromise = null;
return sessionInfo;
}).catch(function (err) {
if (!(err.response && err.response.status)) {
throw new Error('There was a problem getting new session info. Please check your configuration settings.');
}
throw err;
});
}
return this._updatedSessionInfoPromise;
}
}, {
key: '_handleNewSessionInfo',
value: function _handleNewSessionInfo(sessionResponse) {
var _this6 = this;
return Promise.all([{
accessToken: sessionResponse.accessToken,
expiresAt: sessionResponse.expiresIn * 1000 + Date.now()
}, this._getApiToken(sessionResponse.accessToken)]).then(function (_ref2) {
var _ref3 = slicedToArray(_ref2, 2),
partialSessionInfo = _ref3[0],
apiToken = _ref3[1];
var sessionInfo = _extends({}, partialSessionInfo, {
apiToken: apiToken
});
_this6._saveSession(sessionInfo);
_this6._scheduleTokenRenewal();
return sessionInfo;
});
}
}, {
key: '_loadSession',

@@ -1571,3 +1633,3 @@ value: function _loadSession() {

apiToken: localStorage.getItem('api_token'),
expiresAt: localStorage.getItem('expires_at')
expiresAt: JSON.parse(localStorage.getItem('expires_at'))
};

@@ -1579,6 +1641,6 @@ }

value: function _parseWebAuthHash() {
var _this5 = this;
var _this7 = this;
return new Promise(function (resolve, reject) {
_this5._auth0.parseHash(function (err, hashResponse) {
_this7._auth0.parseHash(function (err, hashResponse) {
if (err || !hashResponse) {

@@ -1600,4 +1662,22 @@ return reject(err || new Error('No valid tokens returned from auth0'));

localStorage.setItem('api_token', sessionInfo.apiToken);
localStorage.setItem('expires_at', sessionInfo.expiresAt);
localStorage.setItem('expires_at', JSON.stringify(sessionInfo.expiresAt));
}
}, {
key: '_scheduleTokenRenewal',
value: function _scheduleTokenRenewal() {
var _this8 = this;
var tokenExpiresAtBufferMs = this._sdk.config.auth.tokenExpiresAtBufferMs || 0;
var bufferedExpiresAt = this._sessionInfo.expiresAt - tokenExpiresAtBufferMs;
var delay = bufferedExpiresAt - Date.now();
if (this._tokenRenewalTimeout) {
clearTimeout(this._tokenRenewalTimeout);
}
this._tokenRenewalTimeout = setTimeout(function () {
_this8._getUpdatedSessionInfo();
}, delay);
}
}]);

@@ -1604,0 +1684,0 @@ return Auth0WebAuth;

@@ -1409,2 +1409,6 @@ 'use strict';

});
if (this.isAuthenticated()) {
this._scheduleTokenRenewal();
}
}

@@ -1453,18 +1457,3 @@

return this._parseWebAuthHash().then(function (hash) {
return Promise.all([{
accessToken: hash.accessToken,
expiresAt: hash.expiresIn * 1000 + Date.now()
}, _this2._getApiToken(hash.accessToken)]);
}).then(function (_ref) {
var _ref2 = slicedToArray(_ref, 2),
partialSessionInfo = _ref2[0],
apiToken = _ref2[1];
var sessionInfo = _extends({}, partialSessionInfo, {
apiToken: apiToken
});
_this2._saveSession(sessionInfo);
return sessionInfo;
return _this2._handleNewSessionInfo(hash);
}).then(function (sessionInfo) {

@@ -1490,3 +1479,3 @@ var redirectPathname = _this2._getRedirectPathname();

return hasTokens && this._sessionInfo.expiresAt > Date.now();
return hasTokens;
}

@@ -1509,2 +1498,4 @@

clearTimeout(this._tokenRenewalTimeout);
this._onRedirect('/');

@@ -1514,2 +1505,20 @@ }

}, {
key: '_checkSession',
value: function _checkSession() {
var _this3 = this;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return new Promise(function (resolve, reject) {
_this3._auth0.checkSession(options, function (err, response) {
if (err || !response) {
return reject(err || new Error('No valid tokens returned from auth0'));
}
return resolve(response);
});
});
}
}, {
key: '_defaultOnRedirect',

@@ -1523,9 +1532,9 @@ value: function _defaultOnRedirect(pathname) {

value: function _getApiToken(accessToken) {
var _this3 = this;
var _this4 = this;
return axios.post(this._sdk.config.audiences.contxtAuth.host + '/v1/token', {
audiences: Object.keys(this._sdk.config.audiences).map(function (audienceName) {
return _this3._sdk.config.audiences[audienceName].clientId;
return _this4._sdk.config.audiences[audienceName].clientId;
}).filter(function (clientId) {
return clientId !== _this3._sdk.config.audiences.contxtAuth.clientId;
return clientId !== _this4._sdk.config.audiences.contxtAuth.clientId;
}),

@@ -1535,4 +1544,4 @@ nonce: 'nonce'

headers: { Authorization: 'Bearer ' + accessToken }
}).then(function (_ref3) {
var data = _ref3.data;
}).then(function (_ref) {
var data = _ref.data;
return data.access_token;

@@ -1545,12 +1554,17 @@ });

value: function _getCurrentTokenByType(type) {
var _this4 = this;
var propertyName = type + 'Token';
var tokenExpiresAtBufferMs = this._sdk.config.auth.tokenExpiresAtBufferMs || 0;
var bufferedExpiresAt = this._sessionInfo.expiresAt - tokenExpiresAtBufferMs;
var needsNewToken = Date.now() > bufferedExpiresAt;
return new Promise(function (resolve, reject) {
var propertyName = type + 'Token';
if (!needsNewToken && this._sessionInfo[propertyName]) {
return Promise.resolve(this._sessionInfo[propertyName]);
}
if (!(_this4._sessionInfo && _this4._sessionInfo[propertyName])) {
reject(new Error('No ' + type + ' token found'));
return this._getUpdatedSessionInfo().then(function (sessionInfo) {
if (!sessionInfo[propertyName]) {
throw new Error('No ' + type + ' token found');
}
resolve(_this4._sessionInfo[propertyName]);
return sessionInfo[propertyName];
});

@@ -1569,2 +1583,50 @@ }

}, {
key: '_getUpdatedSessionInfo',
value: function _getUpdatedSessionInfo() {
var _this5 = this;
if (!this._updatedSessionInfoPromise) {
this._updatedSessionInfoPromise = this._checkSession().then(function (sessionInfo) {
return _this5._handleNewSessionInfo(sessionInfo);
}).then(function (sessionInfo) {
_this5._updatedSessionInfoPromise = null;
return sessionInfo;
}).catch(function (err) {
if (!(err.response && err.response.status)) {
throw new Error('There was a problem getting new session info. Please check your configuration settings.');
}
throw err;
});
}
return this._updatedSessionInfoPromise;
}
}, {
key: '_handleNewSessionInfo',
value: function _handleNewSessionInfo(sessionResponse) {
var _this6 = this;
return Promise.all([{
accessToken: sessionResponse.accessToken,
expiresAt: sessionResponse.expiresIn * 1000 + Date.now()
}, this._getApiToken(sessionResponse.accessToken)]).then(function (_ref2) {
var _ref3 = slicedToArray(_ref2, 2),
partialSessionInfo = _ref3[0],
apiToken = _ref3[1];
var sessionInfo = _extends({}, partialSessionInfo, {
apiToken: apiToken
});
_this6._saveSession(sessionInfo);
_this6._scheduleTokenRenewal();
return sessionInfo;
});
}
}, {
key: '_loadSession',

@@ -1575,3 +1637,3 @@ value: function _loadSession() {

apiToken: localStorage.getItem('api_token'),
expiresAt: localStorage.getItem('expires_at')
expiresAt: JSON.parse(localStorage.getItem('expires_at'))
};

@@ -1583,6 +1645,6 @@ }

value: function _parseWebAuthHash() {
var _this5 = this;
var _this7 = this;
return new Promise(function (resolve, reject) {
_this5._auth0.parseHash(function (err, hashResponse) {
_this7._auth0.parseHash(function (err, hashResponse) {
if (err || !hashResponse) {

@@ -1604,4 +1666,22 @@ return reject(err || new Error('No valid tokens returned from auth0'));

localStorage.setItem('api_token', sessionInfo.apiToken);
localStorage.setItem('expires_at', sessionInfo.expiresAt);
localStorage.setItem('expires_at', JSON.stringify(sessionInfo.expiresAt));
}
}, {
key: '_scheduleTokenRenewal',
value: function _scheduleTokenRenewal() {
var _this8 = this;
var tokenExpiresAtBufferMs = this._sdk.config.auth.tokenExpiresAtBufferMs || 0;
var bufferedExpiresAt = this._sessionInfo.expiresAt - tokenExpiresAtBufferMs;
var delay = bufferedExpiresAt - Date.now();
if (this._tokenRenewalTimeout) {
clearTimeout(this._tokenRenewalTimeout);
}
this._tokenRenewalTimeout = setTimeout(function () {
_this8._getUpdatedSessionInfo();
}, delay);
}
}]);

@@ -1608,0 +1688,0 @@ return Auth0WebAuth;

{
"name": "@ndustrial/contxt-sdk",
"version": "0.0.14",
"version": "0.0.15",
"description": "",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -30,2 +30,9 @@ import auth0 from 'auth0-js';

*
* This SessionType is set up to refresh auth tokens automatically. To ensure this works, make sure
* your single page application has {@link https://auth0.com/docs/cross-origin-authentication#configure-your-application-for-cross-origin-authentication Cross-Origin Authentication}
* enabled in Auth0.
*
* *NOTE*: The web origin added in auth0 should be something like
* "http://localhost:5000", not "http://localhost:5000/callback"
*
* @type SessionType

@@ -86,2 +93,6 @@ *

});
if (this.isAuthenticated()) {
this._scheduleTokenRenewal();
}
}

@@ -146,21 +157,3 @@

return this._parseWebAuthHash()
.then((hash) => {
return Promise.all([
{
accessToken: hash.accessToken,
expiresAt: hash.expiresIn * 1000 + Date.now()
},
this._getApiToken(hash.accessToken)
]);
})
.then(([partialSessionInfo, apiToken]) => {
const sessionInfo = {
...partialSessionInfo,
apiToken
};
this._saveSession(sessionInfo);
return sessionInfo;
})
.then((hash) => this._handleNewSessionInfo(hash))
.then((sessionInfo) => {

@@ -195,3 +188,3 @@ const redirectPathname = this._getRedirectPathname();

return hasTokens && this._sessionInfo.expiresAt > Date.now();
return hasTokens;
}

@@ -207,3 +200,4 @@

/**
* Logs the user out by removing any stored session info and redirecting to the root
* Logs the user out by removing any stored session info, clearing any token renewal, and
* redirecting to the root
*/

@@ -217,2 +211,4 @@ logOut() {

clearTimeout(this._tokenRenewalTimeout);
this._onRedirect('/');

@@ -222,2 +218,25 @@ }

/**
* Wraps Auth0's `checkSession` method. Will check if the current Auth0 session is valid and get
* updated information if needed
*
* @fulfill {Object} sessionResponse Information returned from Auth0
* @rejects {Error}
*
* @private
*/
_checkSession(options = {}) {
return new Promise((resolve, reject) => {
this._auth0.checkSession(options, (err, response) => {
if (err || !response) {
return reject(
err || new Error('No valid tokens returned from auth0')
);
}
return resolve(response);
});
});
}
/**
* Default method used for redirecting around the web application. Overridden by `onRedirect` in

@@ -264,3 +283,4 @@ * the auth config

/**
* Returns the type of token requested if it exists.
* Returns the type of token requested if it exists. Will get an updated token if the existing
* tokens have expired.
*

@@ -276,10 +296,19 @@ * @param {string} type The type of token requested. Only valid types are `access` and `api`

_getCurrentTokenByType(type) {
return new Promise((resolve, reject) => {
const propertyName = `${type}Token`;
const propertyName = `${type}Token`;
const tokenExpiresAtBufferMs =
this._sdk.config.auth.tokenExpiresAtBufferMs || 0;
const bufferedExpiresAt =
this._sessionInfo.expiresAt - tokenExpiresAtBufferMs;
const needsNewToken = Date.now() > bufferedExpiresAt;
if (!(this._sessionInfo && this._sessionInfo[propertyName])) {
reject(new Error(`No ${type} token found`));
if (!needsNewToken && this._sessionInfo[propertyName]) {
return Promise.resolve(this._sessionInfo[propertyName]);
}
return this._getUpdatedSessionInfo().then((sessionInfo) => {
if (!sessionInfo[propertyName]) {
throw new Error(`No ${type} token found`);
}
resolve(this._sessionInfo[propertyName]);
return sessionInfo[propertyName];
});

@@ -302,2 +331,64 @@ }

/**
* Gets up to date session info. Will get an updated session/tokens if the previous session has
* already expired.
*
* @returns {Promise}
* @fulfills {Auth0WebAuthSessionInfo} sessionInfo
* @rejects {Error}
*
* @private
*/
_getUpdatedSessionInfo() {
if (!this._updatedSessionInfoPromise) {
this._updatedSessionInfoPromise = this._checkSession()
.then((sessionInfo) => this._handleNewSessionInfo(sessionInfo))
.then((sessionInfo) => {
this._updatedSessionInfoPromise = null;
return sessionInfo;
})
.catch((err) => {
if (!(err.response && err.response.status)) {
throw new Error(
'There was a problem getting new session info. Please check your configuration settings.'
);
}
throw err;
});
}
return this._updatedSessionInfoPromise;
}
/**
* Takes Auth0 Session Info, retrieves a Contxt API token, packages them up together, saves the
* tokens, and schedules a renewal.
*
* @returns {Promise}
* @fulfills {Auth0WebAuthSessionInfo} sessionInfo
*
* @private
*/
_handleNewSessionInfo(sessionResponse) {
return Promise.all([
{
accessToken: sessionResponse.accessToken,
expiresAt: sessionResponse.expiresIn * 1000 + Date.now()
},
this._getApiToken(sessionResponse.accessToken)
]).then(([partialSessionInfo, apiToken]) => {
const sessionInfo = {
...partialSessionInfo,
apiToken
};
this._saveSession(sessionInfo);
this._scheduleTokenRenewal();
return sessionInfo;
});
}
/**
* Loads a saved session from local storage

@@ -316,3 +407,3 @@ *

apiToken: localStorage.getItem('api_token'),
expiresAt: localStorage.getItem('expires_at')
expiresAt: JSON.parse(localStorage.getItem('expires_at'))
};

@@ -359,4 +450,25 @@ }

localStorage.setItem('api_token', sessionInfo.apiToken);
localStorage.setItem('expires_at', sessionInfo.expiresAt);
localStorage.setItem('expires_at', JSON.stringify(sessionInfo.expiresAt));
}
/**
* Schedules the Access and API tokens to renew before they expire
*
* @private
*/
_scheduleTokenRenewal() {
const tokenExpiresAtBufferMs =
this._sdk.config.auth.tokenExpiresAtBufferMs || 0;
const bufferedExpiresAt =
this._sessionInfo.expiresAt - tokenExpiresAtBufferMs;
const delay = bufferedExpiresAt - Date.now();
if (this._tokenRenewalTimeout) {
clearTimeout(this._tokenRenewalTimeout);
}
this._tokenRenewalTimeout = setTimeout(() => {
this._getUpdatedSessionInfo();
}, delay);
}
}

@@ -363,0 +475,0 @@

@@ -24,3 +24,4 @@ import auth0 from 'auth0-js';

authorizationPath: faker.hacker.noun(),
clientId: faker.internet.password()
clientId: faker.internet.password(),
tokenExpiresAtBufferMs: faker.random.number()
}

@@ -58,2 +59,5 @@ }

this.sandbox
.stub(Auth0WebAuth.prototype, 'isAuthenticated')
.returns(false);
loadSession = this.sandbox

@@ -115,2 +119,3 @@ .stub(Auth0WebAuth.prototype, '_loadSession')

this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
this.sandbox.stub(Auth0WebAuth.prototype, '_scheduleTokenRenewal');

@@ -132,2 +137,23 @@ auth0WebAuth = new Auth0WebAuth(sdk);

context('when currently authenticated', function() {
let scheduleTokenRenewal;
beforeEach(function() {
this.sandbox
.stub(Auth0WebAuth.prototype, 'isAuthenticated')
.returns(true);
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
scheduleTokenRenewal = this.sandbox.stub(
Auth0WebAuth.prototype,
'_scheduleTokenRenewal'
);
const auth0WebAuth = new Auth0WebAuth(sdk); // eslint-disable-line no-unused-vars
});
it('schedules a future token renewal', function() {
expect(scheduleTokenRenewal).to.be.calledOnce;
});
});
context('without required config options', function() {

@@ -257,10 +283,10 @@ beforeEach(function() {

let clock;
let expectedHash;
let expectedRedirectPathname;
let expectedSessionInfo;
let getApiToken;
let getRedirectPathname;
let handleNewSessionInfo;
let onRedirect;
let parseWebAuthHash;
let promise;
let saveSession;

@@ -275,12 +301,15 @@ beforeEach(function() {

};
expectedHash = {
accessToken: expectedSessionInfo.accessToken,
expiresIn:
(expectedSessionInfo.expiresAt - currentDate.getTime()) / 1000
};
clock = sinon.useFakeTimers(currentDate);
getApiToken = this.sandbox
.stub(Auth0WebAuth.prototype, '_getApiToken')
.callsFake(() => {
return Promise.resolve(expectedSessionInfo.apiToken);
});
getRedirectPathname = this.sandbox
.stub(Auth0WebAuth.prototype, '_getRedirectPathname')
.returns(expectedRedirectPathname);
handleNewSessionInfo = this.sandbox
.stub(Auth0WebAuth.prototype, '_handleNewSessionInfo')
.resolves(expectedSessionInfo);
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');

@@ -290,19 +319,3 @@ onRedirect = this.sandbox.stub();

.stub(Auth0WebAuth.prototype, '_parseWebAuthHash')
.callsFake(() => {
return Promise.resolve({
accessToken: expectedSessionInfo.accessToken,
expiresIn:
(expectedSessionInfo.expiresAt - currentDate.getTime()) / 1000
});
});
saveSession = this.sandbox.stub(Auth0WebAuth.prototype, '_saveSession');
global.window = {
_location: `${faker.internet.url()}/${faker.hacker.adjective()}`,
get location() {
return this._location;
},
set location(newLocation) {
this._location = newLocation;
}
};
.resolves(expectedHash);

@@ -322,15 +335,8 @@ const auth0WebAuth = new Auth0WebAuth(sdk);

it('gets a contxt api token using the web auth access token', function() {
it('handles getting any other needed new session info', function() {
return promise.then(() => {
expect(getApiToken).to.be.calledOnce;
expect(getApiToken).to.be.calledWith(expectedSessionInfo.accessToken);
expect(handleNewSessionInfo).to.be.calledWith(expectedHash);
});
});
it('saves the session info to local storage for future use', function() {
return promise.then(() => {
expect(saveSession).to.be.calledWith(expectedSessionInfo);
});
});
it('gets a stored (or default redirect pathname)', function() {

@@ -363,7 +369,2 @@ return promise.then(() => {

this.sandbox
.stub(Auth0WebAuth.prototype, '_getApiToken')
.callsFake(() => {
return Promise.reject(expectedError);
});
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');

@@ -373,5 +374,3 @@ onRedirect = this.sandbox.stub();

.stub(Auth0WebAuth.prototype, '_parseWebAuthHash')
.callsFake(() => {
return Promise.resolve({});
});
.rejects(new Error(expectedError));
global.window = {

@@ -413,26 +412,2 @@ _location: `${faker.internet.url()}/${faker.hacker.adjective()}`,

it('returns true when the expiresAt info is in the future', function() {
auth0WebAuth._sessionInfo = {
accessToken: faker.internet.url(),
apiToken: faker.internet.url(),
expiresAt: faker.date.future().getTime()
};
const isAuthenticated = auth0WebAuth.isAuthenticated();
expect(isAuthenticated).to.be.true;
});
it('returns false when the expiresAt info is in the past', function() {
auth0WebAuth._sessionInfo = {
accessToken: faker.internet.url(),
apiToken: faker.internet.url(),
expiresAt: faker.date.past().getTime()
};
const isAuthenticated = auth0WebAuth.isAuthenticated();
expect(isAuthenticated).to.be.false;
});
it('returns false when there is no stored session info', function() {

@@ -495,2 +470,4 @@ const isAuthenticated = auth0WebAuth.isAuthenticated();

let auth0WebAuth;
let clearTimeout;
let expectedTokenRenewalTimeout;
let onRedirect;

@@ -500,2 +477,5 @@ let localStorage;

beforeEach(function() {
expectedTokenRenewalTimeout = faker.helpers.createTransaction();
clearTimeout = this.sandbox.stub(global, 'clearTimeout');
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');

@@ -507,2 +487,3 @@ localStorage = {

onRedirect = this.sandbox.stub();
this.sandbox.stub(Auth0WebAuth.prototype, '_scheduleTokenRenewal');

@@ -516,2 +497,3 @@ auth0WebAuth = new Auth0WebAuth(sdk);

};
auth0WebAuth._tokenRenewalTimeout = expectedTokenRenewalTimeout;
auth0WebAuth.logOut();

@@ -540,2 +522,6 @@ });

it('clears the existing token renewal timeout', function() {
expect(clearTimeout).to.be.calledWith(expectedTokenRenewalTimeout);
});
it("redirects to the browser's location", function() {

@@ -546,2 +532,62 @@ expect(onRedirect).to.be.calledWith('/');

describe('_checkSession', function() {
context('when the session is successfully checked', function() {
let expectedOptions;
let expectedSessionInfo;
let promise;
beforeEach(function() {
expectedOptions = faker.helpers.createTransaction();
expectedSessionInfo = {
accessToken: faker.internet.password(),
apiToken: faker.internet.password(),
expiresAt: faker.date.future().getTime()
};
webAuthSession.checkSession = this.sandbox
.stub()
.callsFake((options, cb) => {
cb(null, expectedSessionInfo);
});
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
const auth0WebAuth = new Auth0WebAuth(sdk);
promise = auth0WebAuth._checkSession(expectedOptions);
});
it('checks for an up to date session', function() {
expect(webAuthSession.checkSession).to.be.calledWith(expectedOptions);
});
it('resolves with the up to date session info', function() {
return expect(promise).to.be.fulfilled.and.to.eventually.equal(
expectedSessionInfo
);
});
});
context('when there is an issue checking the session', function() {
let expectedError;
let promise;
beforeEach(function() {
expectedError = new Error(faker.hacker.phrase());
webAuthSession.checkSession = this.sandbox
.stub()
.callsFake((options, cb) => {
cb(expectedError);
});
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
const auth0WebAuth = new Auth0WebAuth(sdk);
promise = auth0WebAuth._checkSession();
});
it('returns with a rejected promise', function() {
return expect(promise).to.be.rejectedWith(expectedError);
});
});
});
describe('_defaultOnRedirect', function() {

@@ -609,28 +655,117 @@ let expectedPathname;

describe('_getCurrentTokenByType', function() {
let auth0WebAuth;
context('when there are no existing tokens', function() {
context('when successfully getting the requested token', function() {
let expectedSessionInfo;
let getUpdatedSessionInfo;
let promise;
let tokenType;
beforeEach(function() {
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
beforeEach(function() {
expectedSessionInfo = {
accessToken: faker.internet.password(),
apiToken: faker.internet.password()
};
tokenType = faker.random.arrayElement(
Object.keys(expectedSessionInfo)
);
auth0WebAuth = new Auth0WebAuth(sdk);
});
getUpdatedSessionInfo = this.sandbox
.stub(Auth0WebAuth.prototype, '_getUpdatedSessionInfo')
.resolves(expectedSessionInfo);
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
it('returns a rejected promise when there is no current token of that type', function() {
const type = faker.hacker.adjective();
const promise = auth0WebAuth._getCurrentTokenByType(type);
const auth0WebAuth = new Auth0WebAuth(sdk);
auth0WebAuth._sessionInfo = {
expiresAt: faker.date.past().getTime()
};
promise = auth0WebAuth._getCurrentTokenByType(
tokenType.replace(/Token$/, '')
);
});
return expect(promise).to.be.rejectedWith(`No ${type} token found`);
});
it('gets updated session info', function() {
expect(getUpdatedSessionInfo).to.be.calledOnce;
});
it('returns a resolved promise with the current token', function() {
const type = faker.hacker.adjective();
const expectedToken = faker.internet.password();
it('resolves with the requested token info', function() {
return expect(promise).to.be.fulfilled.and.to.eventually.equal(
expectedSessionInfo[tokenType]
);
});
});
auth0WebAuth._sessionInfo = { [`${type}Token`]: expectedToken };
const promise = auth0WebAuth._getCurrentTokenByType(type);
context(
'when requesting a token type that does not exist in the session info',
function() {
let promise;
let tokenType;
return expect(promise).to.be.fulfilled.and.to.eventually.equal(
expectedToken
beforeEach(function() {
tokenType = faker.hacker.adjective();
this.sandbox
.stub(Auth0WebAuth.prototype, '_getUpdatedSessionInfo')
.resolves({
accessToken: faker.internet.password(),
apiToken: faker.internet.password()
});
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
const auth0WebAuth = new Auth0WebAuth(sdk);
auth0WebAuth._sessionInfo = {
expiresAt: faker.date.past().getTime()
};
promise = auth0WebAuth._getCurrentTokenByType(tokenType);
});
it('returns a rejected promise', function() {
return expect(promise).to.be.rejectedWith(
`No ${tokenType} token found`
);
});
}
);
});
context('when there is an existing, non-expired token', function() {
let expectedSessionInfo;
let getUpdatedSessionInfo;
let promise;
let tokenType;
beforeEach(function() {
expectedSessionInfo = {
accessToken: faker.internet.password(),
apiToken: faker.internet.password(),
// Add buffer to ensure date is in the future
expiresAt:
faker.date.future().getTime() +
sdk.config.auth.tokenExpiresAtBufferMs
};
tokenType = faker.random.arrayElement(
Object.keys(omit(expectedSessionInfo, ['expiresAt']))
);
getUpdatedSessionInfo = this.sandbox
.stub(Auth0WebAuth.prototype, '_getUpdatedSessionInfo')
.resolves({});
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
const auth0WebAuth = new Auth0WebAuth(sdk);
auth0WebAuth._sessionInfo = expectedSessionInfo;
promise = auth0WebAuth._getCurrentTokenByType(
tokenType.replace(/Token$/, '')
);
});
it('does not get updated session info', function() {
expect(getUpdatedSessionInfo).to.not.be.called;
});
it('resolves with the requested token info', function() {
return expect(promise).to.be.fulfilled.and.to.eventually.equal(
expectedSessionInfo[tokenType]
);
});
});
});

@@ -699,2 +834,177 @@

describe('_getUpdatedSessionInfo', function() {
context('when there is no existing request for session info', function() {
context('when successfully updating session info', function() {
let auth0WebAuth;
let checkSession;
let expectedSessionInfo;
let handleNewSessionInfo;
let promise;
beforeEach(function() {
expectedSessionInfo = {
accessToken: faker.internet.password(),
apiToken: faker.internet.password(),
expiresAt: faker.date.future().getTime()
};
checkSession = this.sandbox
.stub(Auth0WebAuth.prototype, '_checkSession')
.resolves(expectedSessionInfo);
handleNewSessionInfo = this.sandbox
.stub(Auth0WebAuth.prototype, '_handleNewSessionInfo')
.resolves(expectedSessionInfo);
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
auth0WebAuth = new Auth0WebAuth(sdk);
promise = auth0WebAuth._getUpdatedSessionInfo();
});
it('sets the stored promise in the class instance', function() {
expect(auth0WebAuth._updatedSessionInfoPromise).to.be.a('promise');
});
it('checks the existing session for updated session info', function() {
expect(checkSession).to.be.calledOnce;
});
it('handles the new session info', function() {
return promise.then(() => {
expect(handleNewSessionInfo).to.be.calledWith(expectedSessionInfo);
});
});
it('resets the stored promise in the class instance', function() {
return promise.then(() => {
expect(auth0WebAuth._updatedSessionInfoPromise).to.be.null;
});
});
it('resolves with the new session info', function() {
return expect(promise).to.be.fulfilled.and.to.eventually.equal(
expectedSessionInfo
);
});
});
context('when there is an error getting the session info', function() {
beforeEach(function() {
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
});
it('throws a human readable error when unable to reach the server', function() {
this.sandbox
.stub(Auth0WebAuth.prototype, '_checkSession')
.rejects(new Error());
const auth0WebAuth = new Auth0WebAuth(sdk);
const promise = auth0WebAuth._getUpdatedSessionInfo();
return expect(promise).to.be.rejectedWith(
'There was a problem getting new session info. Please check your configuration settings.'
);
});
it('throws a human readable error when unable to reach one of the servers', function() {
const expectedError = new Error();
expectedError.response = { status: faker.random.number() };
this.sandbox
.stub(Auth0WebAuth.prototype, '_checkSession')
.rejects(expectedError);
const auth0WebAuth = new Auth0WebAuth(sdk);
const promise = auth0WebAuth._getUpdatedSessionInfo();
return expect(promise).to.be.rejectedWith(expectedError);
});
});
});
context(
'when there is an existing request for new session info',
function() {
let expectedPromise;
let promise;
beforeEach(function() {
expectedPromise = new Promise(() => {});
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
const auth0WebAuth = new Auth0WebAuth(sdk);
auth0WebAuth._updatedSessionInfoPromise = expectedPromise;
promise = auth0WebAuth._getUpdatedSessionInfo();
});
it('returns the existing promise', function() {
expect(promise).to.equal(expectedPromise);
});
}
);
});
describe('_handleNewSessionInfo', function() {
let clock;
let expectedSessionInfo;
let getApiToken;
let promise;
let saveSession;
let scheduleTokenRenewal;
beforeEach(function() {
const currentDate = new Date();
expectedSessionInfo = {
accessToken: faker.internet.password(),
apiToken: faker.internet.password(),
expiresAt: faker.date.future().getTime()
};
clock = sinon.useFakeTimers(currentDate);
getApiToken = this.sandbox
.stub(Auth0WebAuth.prototype, '_getApiToken')
.resolves(expectedSessionInfo.apiToken);
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
saveSession = this.sandbox.stub(Auth0WebAuth.prototype, '_saveSession');
scheduleTokenRenewal = this.sandbox.stub(
Auth0WebAuth.prototype,
'_scheduleTokenRenewal'
);
const auth0WebAuth = new Auth0WebAuth(sdk);
promise = auth0WebAuth._handleNewSessionInfo({
accessToken: expectedSessionInfo.accessToken,
expiresIn:
(expectedSessionInfo.expiresAt - currentDate.getTime()) / 1000
});
});
afterEach(function() {
clock.restore();
});
it('gets a contxt api token using the web auth access token', function() {
return promise.then(() => {
expect(getApiToken).to.be.calledWith(expectedSessionInfo.accessToken);
});
});
it('saves the updated session info', function() {
return promise.then(() => {
expect(saveSession).to.be.calledWith(expectedSessionInfo);
});
});
it('schedules the next token renewal', function() {
return promise.then(() => {
expect(scheduleTokenRenewal).to.be.calledOnce;
});
});
it('resolves with new session info', function() {
return expect(promise).to.be.fulfilled.and.to.eventually.deep.equal(
expectedSessionInfo
);
});
});
describe('_loadSession', function() {

@@ -713,2 +1023,5 @@ let auth0WebAuth;

this.sandbox
.stub(Auth0WebAuth.prototype, 'isAuthenticated')
.returns(false);
localStorage = {

@@ -722,3 +1035,3 @@ getItem: this.sandbox.stub().callsFake((key) => {

case 'expires_at':
return expectedSessionInfo.expiresAt;
return `${expectedSessionInfo.expiresAt}`;
}

@@ -745,3 +1058,3 @@ })

it('gets the expires at information out of local storage', function() {
it('gets the expires at information out of local storage (and coreces it to be a number)', function() {
expect(localStorage.getItem).to.be.calledWith('expires_at');

@@ -871,9 +1184,67 @@ });

it('saves the expires at information to local storage', function() {
it('saves the expires at information to local storage (as a string)', function() {
expect(localStorage.setItem).to.be.calledWith(
'expires_at',
expectedSessionInfo.expiresAt
`${expectedSessionInfo.expiresAt}`
);
});
});
describe('_scheduleTokenRenewal', function() {
let auth0WebAuth;
let clock;
let expectedDelay;
let getUpdatedSessionInfo;
let initialTimeout;
beforeEach(function() {
const currentDate = new Date();
clock = sinon.useFakeTimers(currentDate);
const expiresAt = faker.date.future().getTime();
expectedDelay =
expiresAt -
sdk.config.auth.tokenExpiresAtBufferMs -
currentDate.getTime();
initialTimeout = clock.setTimeout(() => {}, 0);
this.sandbox.spy(clock, 'clearTimeout');
this.sandbox.stub(Auth0WebAuth.prototype, '_loadSession');
getUpdatedSessionInfo = this.sandbox.stub(
Auth0WebAuth.prototype,
'_getUpdatedSessionInfo'
);
this.sandbox.spy(clock, 'setTimeout');
auth0WebAuth = new Auth0WebAuth(sdk);
auth0WebAuth._sessionInfo = { expiresAt };
auth0WebAuth._tokenRenewalTimeout = initialTimeout;
auth0WebAuth._scheduleTokenRenewal();
});
afterEach(function() {
clock.restore();
});
it('clears any existing renewal timeout', function() {
expect(clock.clearTimeout).to.be.calledWith(initialTimeout);
});
it('sets up a renewal timeout', function() {
expect(auth0WebAuth._tokenRenewalTimeout).to.not.equal(initialTimeout);
expect(auth0WebAuth._tokenRenewalTimeout).to.be.an('object');
expect(auth0WebAuth._tokenRenewalTimeout.id).to.be.a('number');
expect(clock.setTimeout).to.be.calledOnce;
const [cb, delay] = clock.setTimeout.firstCall.args;
expect(cb).to.be.a('function');
expect(delay).to.equal(expectedDelay);
});
it('updates the session info after the delay', function() {
clock.tick(expectedDelay);
expect(getUpdatedSessionInfo).to.be.calledOnce;
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc