1

I am using OAuth with access/refresh tokens. I have followed these examples to try and catch unauthorized http calls, refresh tokens automatically, and then use the new tokens to retry the call:

Handling refresh tokens using rxjs

https://www.illucit.com/blog/2016/03/angular2-http-authentication-interceptor/

http://restlet.com/company/blog/2016/04/18/interacting-efficiently-with-a-restful-service-with-angular2-and-rxjs-part-3/

I am extending Angular's Http class and successfully catching 401's. My problem is when I have multiple http calls nearly simultaneously. They all return unauthorized 401. Then they all attempt to refresh the tokens. The first one to reach the server succesfully gets new tokens, and retries its http call with the new tokens. However, all of the other calls are attempting to do the same with the same refresh token without waiting for the first call to return with the new tokens. This is causing an error on the backend.

Ideally the first http call that returns 401 goes through the process of getting new tokens, and all other calls that get intercepted wait for the first one to complete. But based off of the examples I posted, I don't know how to "pause" the latter intercepted 401 errors and wait for returned tokens from the first call.

I am using observables.

Community
  • 1
  • 1
Kevin Quiring
  • 639
  • 1
  • 11
  • 26
  • Hi Kevin, can you please share your idea of how you implemented to meet this requirement. I have the same exact requirement now, where all other API calls fail with 401 because the first API call already consumed the refresh token, making it invalid for all subsequent API calls. – Malathy Sep 20 '18 at 03:45

1 Answers1

0

You could probably set the current refresh tokens observable to a variable on the class, and check if it's not null as your other calls come back as 401s. If its not null, wait for it to complete then try again.

Here's some really basic pseudo code I wrote. I'm not 100% sure it will be functional. I'm also sure there's a more rxjs'y way to retry the original request instead of explicitly calling this.get(url) again

private refreshObservable: Observable<T>;

public get<T>(url: string) : Observable<T> {
    return this.http.get(url)
        .catch(err => {
            //assuming err is a 401..
            return (this.refreshObservable || this.refreshTokens()).flatMap(() => this.get(url));
        })
}

private refreshTokens() {
    return this.refreshObservable = this.http.get('refreshendpoint').do(() => this.refreshObservable = null).share();
}
smoyer
  • 7,932
  • 3
  • 17
  • 26