I want to refresh the token if user gets unauthorized error. I am trying to handle this in interceptors. Below is the code:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
fn.refreshToken(req, next);
}
}
});
}
And I have function refreshToken where I am trying to call an API to refresh token:
refreshToken(req, next) {
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded');
const body = new HttpParams()
.set('refresh_token', localStorage.getItem('refreshToken'));
this._http.post('/refreshtoken', body.toString(), {headers}).subscribe(
(data) => {
const header = `Bearer ${(<any>data).accessToken}`;
const newRequest = req.clone({ headers: req.headers.set('Authorization', header)});
return next.handle(newRequest);
}),
(err) => {
console.log(err);
}
}
But the problem with above code is that I am not able to call the cloned request. The request is triggered only is I call subscribe method to it. As shown below:
return next.handle(newRequest).subscribe();
I want if token is expired, call the service to refresh the token and resend the original request which is failed. Moreover call the subscribe method of original request that is failed.
Please let me know if my approach is correct.
And if yes, then what I am missing here.
The interceptor has to return an Observable and can call next.handle(req)
itself so I think you could call next.handle(req)
twice but even better and more "Rx" solution would be to use the catch
operator and merge the original source Observable. Also you'll need change refreshToken
to return an Observable and you'll probably want to store the new token with do()
.
refreshToken(...): Observable<any> {
return this._http.post('/refreshtoken', ...)
.do(/* save token here */);
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req)
.catch((err, source) => {
if (err instanceof HttpErrorResponse && err.status === 401) {
return this.refreshToken(...)
.concatMap(() => next.handle(req /* ... or updated req */ ));
// or you could use .concatMap(() => source) to trigger the same request again
}
throw err;
})
}