Commit 29af928e authored by Robert Knight's avatar Robert Knight Committed by GitHub

Merge pull request #220 from hypothesis/cache-access-token-promise-not-access-token

Cache access token promise not access token
parents 8620bf98 e15f5740
...@@ -13,7 +13,7 @@ var resolve = require('./util/url-util').resolve; ...@@ -13,7 +13,7 @@ var resolve = require('./util/url-util').resolve;
// @ngInject // @ngInject
function auth($http, settings) { function auth($http, settings) {
var cachedToken; var accessTokenPromise;
var tokenUrl = resolve('token', settings.apiUrl); var tokenUrl = resolve('token', settings.apiUrl);
// Exchange the JWT grant token for an access token. // Exchange the JWT grant token for an access token.
...@@ -36,26 +36,23 @@ function auth($http, settings) { ...@@ -36,26 +36,23 @@ function auth($http, settings) {
} }
function tokenGetter() { function tokenGetter() {
if (cachedToken) { if (!accessTokenPromise) {
return Promise.resolve(cachedToken.token);
} else {
var grantToken; var grantToken;
if (Array.isArray(settings.services) && settings.services.length > 0) { if (Array.isArray(settings.services) && settings.services.length > 0) {
grantToken = settings.services[0].grantToken; grantToken = settings.services[0].grantToken;
} }
if (!grantToken) { if (grantToken) {
return Promise.resolve(null); accessTokenPromise = exchangeToken(grantToken).then(function (tokenInfo) {
return tokenInfo.access_token;
});
} else {
accessTokenPromise = Promise.resolve(null);
} }
return exchangeToken(grantToken).then(function (tokenInfo) {
cachedToken = {
token: tokenInfo.access_token,
};
return cachedToken.token;
});
} }
return accessTokenPromise;
} }
// clearCache() isn't implemented (or needed) yet for OAuth. // clearCache() isn't implemented (or needed) yet for OAuth.
......
...@@ -75,6 +75,31 @@ describe('oauth auth', function () { ...@@ -75,6 +75,31 @@ describe('oauth auth', function () {
}); });
}); });
// If an access token request has already been made but is still in
// flight when tokenGetter() is called again, then it should just return
// the pending Promise for the first request again (and not send a second
// concurrent HTTP request).
it('should not make two concurrent access token requests', function () {
// Make $http.post() return a pending Promise (simulates an in-flight
// HTTP request).
fakeHttp.post.returns(new Promise(function() {}));
// The first time tokenGetter() is called it sends the access token HTTP
// request and returns a Promise for the access token.
var firstAccessTokenPromise = auth.tokenGetter();
// No matter how many times it's called while there's an HTTP request
// in-flight, tokenGetter() never sends a second concurrent HTTP request.
auth.tokenGetter();
auth.tokenGetter();
// It just keeps on returning the same Promise for the access token.
var accessTokenPromise = auth.tokenGetter();
assert.strictEqual(accessTokenPromise, firstAccessTokenPromise);
assert.equal(fakeHttp.post.callCount, 1);
});
it('should return null if no grant token was provided', function () { it('should return null if no grant token was provided', function () {
var auth = authService(fakeHttp, { var auth = authService(fakeHttp, {
services: [{authority: 'publisher.org'}], services: [{authority: 'publisher.org'}],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment