Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scheduling access token refresh across tabs

To authenticate users in my Angular app i use access tokens with expiry time X seconds and refresh tokens that can be used to prolong the auth for another X seconds.

So the flow is this:

  • A user signs in. Both the access and refresh tokens are stored in local storage
  • A timer is set (5% shorter than X seconds).
  • When the timer is done, a refresh token request is sent to the server and the local storage is updated with the resulting (new) access and refresh tokens.

My problem is this:

  • If I have multiple tabs open, I will inevitably end up in situations where the refresh is triggered from multiple tabs at the same time. The server will accept the first request, but throw a 400 Bad Request - Invalid refresh token for the subsequent requests, since it considers them used.

Does anyone have a good idea how this could be solved? How does one synchronize things across tabs/windows? I have a couple of ideas but they all seem a bit far fetched:

  • If the response is 400 Bad Request, then retry in a little while (or check if there is a valid updated token already).
  • Try to synchronize the server requests across tabs by posting messages between them.
like image 993
Joel Avatar asked Jun 12 '17 08:06

Joel


People also ask

Can I use refresh token multiple times?

Refresh tokens never expire, unless revoked by the user.

What is the best way to store refresh token?

Access token and refresh token shouldn't be stored in the local/session storage, because they are not a place for any sensitive data. Hence I would store the access token in a httpOnly cookie (even though there is CSRF) and I need it for most of my requests to the Resource Server anyway.

How do you refresh access tokens?

To refresh the access token, select the Refresh access token API call within the Authorization folder of the Postman collection. Next, click the Send button to request a new access_token .

Are refresh tokens JWTS?

The API returns a short-lived token (JWT), which expires in 15 minutes, and in HTTP cookies, the refresh token expires in 7 days. JWT is currently used for accessing secure ways on API, whereas a refresh token generates another new JWT access token when it expires or even before.


1 Answers

dont set timer , add interceptor and catch error and if you got 401 error , do your refresh token flow and then repeat failed request with new token

intercept(request: HttpRequest<any>, next: HttpHandler): 
        Observable<HttpEvent<any>> {

return next.handle(request).pipe(
  catchError((error: HttpErrorResponse) => {
    if (error.status == 401) {
      return this.refreshToken(request, next);
     } 
    }
    return throwError(error);
  })
);


      private refreshingInProgress: boolean = false;
  private accessTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);

  private refreshToken(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!this.refreshingInProgress) {
      this.refreshingInProgress = true;
      this.accessTokenSubject.next(null);
      return this.authenticationService.refreshToken().pipe(
        switchMap((res: any) => {
          this.refreshingInProgress = false;
          this.accessTokenSubject.next(res);
          // repeat failed request with new token
          return next.handle(this.addToken(request, res));
        })
      );
    } else {
      // wait while getting new token
      return this.accessTokenSubject.pipe(
        filter((token) => token !== null),
        take(1),
        switchMap((token) => {
          // repeat failed request with new token
          return next.handle(this.addToken(request, token));
        })
      );
    }
  }
  
  private addToken(request: HttpRequest<any>, token: Credentials) {
    return request.clone({
      setHeaders: {
        Authorization: `Bearer ${token.access_token}`,
      },
    });
  }
like image 163
farokh veician Avatar answered Oct 02 '22 20:10

farokh veician