Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5 Http Interceptor refreshing JWT token

I already have implemented logic of token saving, retrieving and I have refreshing call also. The problem is that when I intercept 403 in my HttpInterceptor, other calls that are made at the same time, also refresh the token. I would love to hold those calls until my token is refreshed. To create what I would call a 'semaphore' of requests.

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

private auth: AuthService;

constructor(private injector: Injector) {
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.auth = this.injector.get(AuthService);

    if(this.auth.isAuthenticated()){
        request = request.clone({
            setHeaders: {
                Accept: 'application/json',
                Authorization: `Bearer ${localStorage.getItem('access_token')}`
            }
        });
    } else {
        request = request.clone({
            setHeaders: {
                Accept: 'application/json'
            }
        });
    }

    return next.handle(request).catch(error => {
        if (error.status === 401) {
            console.log('refreshing token');

            // TODO: return Refresh Token here and hold other calls
        }

        return Observable.throw(error);
    });
}
like image 532
Bartando Avatar asked Jan 02 '18 12:01

Bartando


People also ask

Can we refresh JWT token?

JWT (JSON Web Token) It may also have a validity period. Once this validity period has elapsed, the server will no longer allow access to resources with this token. In this step, the user will have to get a new access token by reauthentication or with some additional method: refresh token.

Do we need refresh token in JWT?

Since access tokens aren't valid for an extended period because of security reasons, a refresh token helps to re-authenticate a user without login credentials. This Refresh token is never exposed to the client-side Javascript, even if our access token gets compromised it'll be expired in a very short duration.

How often should you refresh JWT token?

The JWT access token is only valid for a finite period of time. Using an expired JWT will cause operations to fail. As you saw above, we are told how long a token is valid through expires_in . This value is normally 1200 seconds or 20 minutes.

How JWT refresh token works Angularjs?

– When the Access Token is expired, Angular automatically sends Refresh Token request, receives new Access Token and uses it for new request. So the server still accepts resource access from the user. – After a period of time, the new Access Token is expired again, and the Refresh Token too.


1 Answers

Well, I'm not able to setup an enviroment to test if this logic works properly, but I tried my best:

Your interceptor should be something like:

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

  private auth: AuthService;

  constructor(private injector: Injector) {
    this.auth = this.injector.get(AuthService);
  }

  setHeaders(request) {
    return function (token) {
      return request.clone({
        setHeaders: {
          Accept: 'application/json',
          Authorization: `Bearer ${token}`
        }
      });
    }
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.auth
      .getToken()
      .map(this.setHeaders(request))
      .mergeMap(next.handle)
      .catch(error => {
        if (error.status === 401) {
          return this.auth.refreshToken()
            .map(this.setHeaders(request))
            .mergeMap(next.handle);
        }
        return Observable.throw(error);
      });
  }

}

And your AuthService:

@Injectable()
export class AuthService {

  private refreshTokenCall;

  saveTokenInLocalStorage(token) {
    localStorage.setItem('access_token', token);
  }

  getToken() {
    if (localStorage.getItem('access_token')) {
      return Observable.of(localStorage.getItem('access_token'));
    }

    return this.refreshToken();
  }

  refreshToken() {
    if (!this.refreshTokenCall) {
      this.refreshTokenCall = this.http.get(refreshTokenURL)
        // Maybe a .map() here, it depends how the backend returns the token
        .do(this.saveTokenInLocalStorage)
        .finally(() => this.refreshTokenCall = null);
    }
    return this.refreshTokenCall;
  }

}

I hope it helps you somehow.

like image 60
Leandro Lima Avatar answered Nov 10 '22 02:11

Leandro Lima