I have implemented a JWT and refresh token flow. When I implemented this in the past, I did it a bit differently, mainly that the refresh token was sent in the body.
But now I've done it differently, and I have to send the access token via the Authorization header, but my interceptor code doesn't want to switch out the bearer token. How do I fix, that if I'm wanting to refresh, I actually use the refresh token as the bearer token instead of the access token that has expired?
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const token = this.userService.getJWTToken();
if (token) {
request = this.addToken(request, token);
}
return next.handle(request).pipe(
catchError((error) => {
if (error instanceof HttpErrorResponse && error.status === 401) {
return this.handle401Error(request, next);
} else if (error.status !== 0) {
return throwError(error);
}
})
);
}
private addToken(request: HttpRequest<any>, token: string): HttpRequest<any> {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
});
}
private handle401Error(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (!this.isRefreshing) {
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
//This is what I've tried, to switch out the tokens
request = this.addToken(request, this.userService.getRefreshToken());
//this.userService.refreshToken() is a POST request, where I want the refresh token as the bearer token, instead of the access token
return this.userService.refreshToken().pipe(
switchMap((token: TokenDTO) => {
this.isRefreshing = false;
this.refreshTokenSubject.next(token.accessToken);
return next.handle(this.addToken(request, token.accessToken));
})
);
} else {
return this.refreshTokenSubject.pipe(
filter((token) => token != null),
take(1),
switchMap((accessToken) =>
next.handle(this.addToken(request, accessToken))
)
);
}
}
I have also tried setting the HTTP header to the authorization bearer token, in the post request
public refreshToken(): Observable<TokenDTO> {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
Authorization: `Bearer ${this.getRefreshToken()}`,
});
return this.httpClient
.post<TokenDTO>(`${this.hostname}/users/refreshToken`, {}, headers)
.pipe(
tap((tokens: TokenDTO) => {
this.saveTokens(tokens);
})
);
}
You should not replace the access token with the bearer token to refresh it, instead you call the dedicated token endpoint with your refresh token to get a new access token. Sometimes, depending on the setup, you might get back a new refresh token as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With