Its purpose is to put the access token (if it’s present) into all requests towards my backend, and if it detects that the access token has expired, to refresh it and retry the request.
Here is the implementation:
@Injectable()
export class MyHttpInterceptor implements HttpInterceptor {
constructor(private store: Store, private configService: ConfigService) {}
intercept(
request: HttpRequest<any>,
handler: HttpHandler
): Observable<HttpEvent<any>> {
if (!request.url.startsWith(this.configService.getBackendBaseURL())) {
return handler.handle(request);
}
return this.store.select(selectAccessToken).pipe(
take(2),
exhaustMap((accessToken) => {
return handler
.handle(
request.clone({
withCredentials: true,
headers:
accessToken == null
? undefined
: new HttpHeaders().set(
'Authorization',
`Bearer ${accessToken}`
),
})
)
.pipe(
catchError((err: HttpErrorResponse) => {
if (accessToken != null && err.status == 401) {
this.store.dispatch(refresh());
return EMPTY;
} else {
return throwError(() => err);
}
})
);
})
);
}
}
To refresh the access token, it dispatches an action that is caught in an effect, which will dispatch another action upon receiving the new access token, which is caught inside a reducer. So after all that, this.store.select(selectAccessToken)
should emit the new access token.
I guess I should actually check if the access token is expired instead of just checking if (accessToken != null && err.status == 401)
, but maybe it’s enough?
This works, but I would like to hear opinions from people with more experience in programming and RxJS. Do you see any potential issues with this implementation, and do you have any suggestions on how to improve this solution?
Also, I realized that I can check if the access token is expired before sending any request. If it is, I can send the refresh request and then the intercepted request. If it isn’t, I only send the intercepted request. That way, I send one less request when the access token expires. However, I would need to add logic to manage cases when a valid access token is not required (like when refreshing the token). Additionally, it adds that step of checking for validity to every request. I guess it’s not much, but still. Do you think this approach is worth it?