I’m writing an OAuth2 API client. Before making an API call I want to check the age of the access token and, if expired, get a new token with a refresh token. So, some code:
page calls something like (WAC is api client):
this.WAC.call('getDailyData', { date: '2016-02-01', gid: 3824 }) .subscribe( response => { console.log("DO STUFF WITH RESPONSE"); }, err => { console.log("FAILED TO GET DAILY DATA: ", err); } );
wac.ts
call(method, params) { ... return this.http.post(url, body, options) .map(res => res.json()); }
The above works just great if the access_token is still valid. However, if it’s no longer valid I need to make another http request to refresh the token. What’s the best way to do this? Is there a way to “interrupt” the process, go refresh the token, and then continue with the call() method to make the API call. Or do I need to return the observable from the refresh_token request and check the response on the subscribe method to determine if the token was just refreshed so then I can re-request the API call? I hope that makes sense.
Thanks,
Brian
Here’s what works, but seems stupid:
this.WAC.call(method, params) // try to make API call
.subscribe(
response => {
if (response.access_token) { // if the response is new token data, we just refreshed, so call the original API method again
this.WAC.setAuthData(response);
this.WAC.call(method, params).subscribe(
response => {
this.displayWods(response);
}
);
} else { // we got actual data back, not just token data from a refresh
this.displayWods(response);
}
},
err => {
console.log("FAILED TO GET DAILY DATA: ", err);
}
);
Inside WAC I have:
call(method, params) {
// check if access_token is expired, if so use refresh token to get a new one
let now = Date.now() / 1000;
if (this.authData.access_expires < now) {
console.log("GOTTA REFRESH!!!!!!");
return this.refreshToken();
} else {
...
return this.http.post(url, body, options)
.map(res => res.json());
}
}
refreshToken() {
...
return this.http.post('http://local.oapi.wodtogether.com/token.php', body, options)
.map(res => res.json());
}
The problem here is that there’s going to be a lot of repeated logic for every API call in order to handle potential token refreshes. Instead of having to check the response for tokendata after each API call, is there a way to move all that logic inside of WAC (api client)?
Thanks!
Yes, I actually have that tab open as well! I just didn’t fully grasp it so I was hoping for another angle. But I’ll dig into it a little more and see what I can get. Thanks
For the benefit of anyone else going through this, here’s what I ended up with (based on the SO topic linked above).
Page.ts – now nice and clean and straight forward
this.WAC.call(method, params)
.subscribe(
response => {
// DO STUFF
},
err => {
// ERROR
}
);
WAC.ts (API Client)
refreshToken() {
...
// call to get a new access token
return this.http.post(this.API_ENDPOINT + '/token.php', body, options);
}
call(method, params) {
// check if access_token is expired, if so use refresh token to get a new one
let now = Date.now() / 1000;
if (this.authData.access_expires < now) {
return this.refreshToken().flatMap(res => {
let res_json = res.json();
this.setAuthData(res_json);
return this.call(method, params);
});
} else {
...
// make the API call
return this.http.post(this.API_ENDPOINT + '/resource.php', body, options)
.map(res => res.json());
}
}
It seems like the flatMap() vs map() was the key – here’s another couple references about the topic:
Thanks again!
Brian