Refresh token requests delayed

Asked

Viewed 194 times

3

How to make the token be created at the same time the method gets:

The way I implemented it, it checks that the token was created, but the token used for the request is the expired token. Only after it runs the Intercept method, it creates the new token.

export class JwtInterceptorService implements HttpInterceptor {

  constructor(
    private authService: AuthService
  ) { }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const header = request.urlWithParams.indexOf('/oauth/token');
    let token = this.authService.getToken();

    console.log('TOKEN', token);

    if (header === -1 &&  this.authService.isAccessTokenInvalid()) {
      this.authService.obterNovoAccessToken();
      token = localStorage.getItem('token');
      console.log('NOVO TOKEN', token);
    }

    if (token && header === -1 && request.url.match(environment.apiUrl)) {
      const cloned = request.clone({
        headers: request.headers.set('Authorization', `Bearer ${token}`)
      });
      return next.handle(cloned);
    } else {
      return next.handle(request);
    }
  }
}
obterNovoAccessToken(): Promise<void> {
    const headers = new HttpHeaders()
      .append('Content-Type', 'application/x-www-form-urlencoded')
      .append('Authorization', 'Basic YW5ndWxhcjpAbmd1bGFyMA==');

    const body = 'grant_type=refresh_token';

    return this.http.post<any>(this.oauthTokenUrl, body, { headers, withCredentials: true })
      .toPromise()
      .then(response => {
        this.armazenarToken(response.access_token);
        return Promise.resolve(null);
      })
      .catch(response => {
        return Promise.resolve(null);
      });
  }
  • 1

    The problem with your code is that you’re treating something asynchronously

1 answer

1


In my case I know that the token is expired or invalid only after I performed the request, so I had to deal with in a catchError, in my case we use rolling token, so I have to update every request and even when the server sends some error they send me one, so I just make the following change.

...
return next.handle(req)
      .pipe(
        catchError(error => {
          const responseError = error as HttpErrorResponse;
          this.authService.token = error; // Aqui eu atualizo o meu token

          if (responseError.status === 401) {
            return this.error401(req, next, error);
          } else if (responseError.status === 403) {
            return this.error403(error);
          }
          return this.otherError(error);
        })
      );

...

In my token I created a get and a set, as follows

  set token(data: any) {
    let token: string;

    if (data && data.headers && data.headers.get('x-access-token') && data.headers.get('x-access-token-type')) {
      token = `${data.headers.get('x-access-token-type')} ${data.headers.get('x-access-token')}`;
      localStorage.setItem(AuthService.TOKEN, token);
    }
  }

  get token() {
    return localStorage.getItem(AuthService.TOKEN);
  }

But I believe you will need to treat your token similar to the way I did to treat the erro 401. Something like:

error401(req: HttpRequest<any>, next: HttpHandler, error: HttpErrorResponse) {
    return this.authService.refresh() // Sua função de renovar o token talvez fique aqui
      .pipe(
        flatMap(() => this.headerInterceptor.intercept(req, next)), // Eu separei em dois interceptors, um para tratar erros e outro apenas para editar o header
        catchError((refreshError) => {
          // Suas tratativas de erro aqui
        })
      );
  }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.