Reputation: 971
I'm doing authorization code flow for oauth2 and there is something I'm doing wrong here but I can't really detect..
Here is my code
In app.js
myService.setup().then(function(){...
In service.js
var service = {
setup(options) {
this.processData();
return this.getToken(options);
},
processData(data) {
let response = this._extractURLParams(window.location.href)
if (response.hasOwnProperty("code")) {
return this.handleAuthorizationCode(responseResult);
},
handleAuthorization(codeObject) {
var service= this;
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("POST", /token, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var params = 'grant_type=authorization_code&code=' + codeObject.code + '&client_id=client_id&client_secret=secret&redirect_uri=' + codeObject.redirectURi;
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var responseData = JSON.parse(this.response);
resolve(service.storeToken(responseData));
}
};
xhr.send(params);
});
},
getToken(options) {
let service = this;
return new Promise(function (resolve, reject) {
if(// localStorage has a token) {
resolve(localStorage.getToken()) //dummy text, real code here
} else {
resolve(service.handleRedirectionsFlow(options));
})
},
What happens is as follows
1) When I access my application, I call myService.setup()
2) the setup() method will call processData(), and since the url will be empty, the if condition will not pass and hence we will call getToken()
3) getToken() will call a method that will build a url and change the location to it so that we authenticate via a form on the authorization server and then we will redirect back to the application after authentication with a code!
4) after authentication, we will redirect to the application with something like 'url?code=abcasdasdsfdasifsfsfs
5) Now, processData() will detect that the url has code property and we will call handleAuthorizationCode
6) handleAuthorizationCode will simply do a post request to get a token and onReadyStateChange we will call another method to store the token.
7) now when we call getToken() from the setup(), at this point the onreadystatechange hasn't been triggered from the previous method, causing that we redo the redirect to authenticate again and then the token request gets cancelled and we never store it..
Could someone help me know where exactly I should put an extra promise and resolve it in order to call getToken() AFTER the onreadystatechange is striggered and the token is stored to avoid the infinite loop?
Thanks
Upvotes: 0
Views: 100
Reputation: 3608
It's hard to know without being able to run it but how about this?
var service = {
setup(options) {
return this.processData()
.then(token => token || this.getToken(options));
},
processData(data) {
const response = this._extractURLParams(window.location.href);
return response.hasOwnProperty("code")
? this.handleAuthorizationCode(responseResult)
: Promise.resolve();
},
handleAuthorization(codeObject) {
var service = this;
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("POST", /token, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var params = 'grant_type=authorization_code&code=' + codeObject.code + '&client_id=client_id&client_secret=secret&redirect_uri=' + codeObject.redirectURi;
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var responseData = JSON.parse(this.response);
resolve(service.storeToken(responseData));
}
};
xhr.send(params);
});
},
getToken(options) {
let service = this;
return new Promise(function(resolve, reject) {
if (localStorageHasToken) {
resolve(localStorage.getToken()) //dummy text, real code here
} else {
resolve(service.handleRedirectionsFlow(options));
}
});
}
};
Essentially we make processData
always return a promise even if it's a promise that resolves immediately and in setup
we wait for processData()
promise to resolve before calling getToken
.
I'm not sure what service.storeToken(responseData)
returns but you can probably use it to skip calling getToken
entirely if the token is already stored.
Upvotes: 1