redux-refresh-token
Version:
A promise callback to refresh access tokens when using RSAA
129 lines (108 loc) • 4.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createFSAConverter = undefined;
exports.default = attemptRefresh;
var _actions = require("./actions");
function attemptRefresh(settings) {
var action = settings.action,
failure = settings.failure,
_settings$isRefreshCa = settings.isRefreshCall,
isRefreshCall = _settings$isRefreshCa === undefined ? defaultIsRefreshCall : _settings$isRefreshCa,
next = settings.next,
refreshActionCreator = settings.refreshActionCreator,
_settings$refreshRedu = settings.refreshReducerKey,
refreshReducerKey = _settings$refreshRedu === undefined ? "tokenRefresh" : _settings$refreshRedu,
_settings$setAccessTo = settings.setAccessTokenActionCreator,
setAccessTokenActionCreator = _settings$setAccessTo === undefined ? _actions.setAccessToken : _settings$setAccessTo,
store = settings.store,
token = settings.token;
return function (response) {
// The API call returned unauthorized user (access token is expired)
if (response.error && response.payload.status === 401 &&
// The refresh endpoint might return 401, so we skip the check here
// otherwise we get stuck in an infinite loop
!isRefreshCall(action, refreshActionCreator()) &&
// We should not run the refresh flow when no token was given to begin with
// (for instance Forgot Password, Login etc.)
typeof token === "string" && token.length > 0) {
// This will ensure that the fail action goes all the way to the bottom
next(response);
// We check if there is already dispatched a call to refresh the token,
// if so we can simply queue the call until the refresh request completes
var refreshPromise = store.getState()[refreshReducerKey].refreshTokenPromise;
if (!refreshPromise) {
refreshPromise = requestNewAccessToken({
store: store,
next: next,
setAccessTokenActionCreator: setAccessTokenActionCreator,
refreshActionCreator: refreshActionCreator
});
next((0, _actions.saveRefreshTokenPromise)(refreshPromise));
}
// When the refresh attempt is done, we fire all the actions that have been queued until
// its completion. If, the refresh promise was unsuccessful we logout the user.
return refreshPromise.then(function (response) {
if (!response.error) {
return store.dispatch(action);
}
return store.dispatch(failure())
// Ensure subscribers do not get an empty response, e.g. T512
.then(function (response) {
return { error: true };
});
});
}
return next(response);
};
}
var requestNewAccessToken = function requestNewAccessToken(_ref) {
var store = _ref.store,
next = _ref.next,
setAccessTokenActionCreator = _ref.setAccessTokenActionCreator,
refreshActionCreator = _ref.refreshActionCreator;
return store.dispatch(refreshActionCreator()).then(function (response) {
// Refresh was successful
next((0, _actions.clearRefreshTokenPromise)());
// Refresh was successful
if (!response.error) {
next(setAccessTokenActionCreator(response.payload));
return {
error: false
};
}
return {
error: true
};
});
};
var defaultIsRefreshCall = function defaultIsRefreshCall(action, refreshAction) {
return action["Call API"].endpoint === refreshAction["Call API"].endpoint;
};
var createFSAConverter = exports.createFSAConverter = function createFSAConverter(successType, failureType) {
return function (response) {
if (!response.ok) {
return {
error: true,
payload: {
status: response.status
},
type: failureType
};
}
var contentType = response.headers.get("Content-Type");
var emptyCodes = [204, 205];
var createSuccessType = function createSuccessType(payload) {
return {
payload: payload,
type: successType
};
};
if (emptyCodes.indexOf(response.status) === -1 && contentType && contentType.indexOf("json") !== -1) {
return response.json().then(createSuccessType);
} else {
return createSuccessType();
}
};
};