I am creating a NestJS application that acts as middleware between this API and something else. I need it to send every request with a Bearer token. If the token is rejected I want it to fetch a new token and retry the same request again.
I'm using an interceptor, and the basics here seem simple enough where I simply add the token to the request headers. However, the other service is always returning a "403 forbidden" error. When I inspect further it seems that the Authorization
header was not actually added to the request!
Here is asimplified version
intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest<Request>();
request.headers.Authorization = this.token;
return next.handle();
}
Is this not the correct way to add an Authorization
header?
Here's my full interceptor code
@Injectable()
export class AuthTokenInterceptor implements NestInterceptor {
private readonly authUrl = "https://...";
private token = "";
constructor(private readonly http: HttpService) {
//Get the token as soon as possible
this.trySaveToken();
}
intercept(context: ExecutionContext, next: CallHandler) {
const request = context.switchToHttp().getRequest<Request>();
if (!request.headers.Authorization) {
request.headers.Authorization = this.token;
}
return next.handle().pipe(
catchError((error: AxiosError) => {
const originalRequest = error.config;
console.log(originalRequest?.headers); //this has no `Authorization` header on it!
//If we have an auth error, we probably just need to re-fetch the token
if (error.response?.status === 401 && originalRequest != null && originalRequest.url !== this.authUrl) {
//without second check, we can loop forever
this.trySaveToken();
originalRequest.headers.Authorization = this.token; //override old default for this request
return of(originalRequest); //retry request with newly added
} else {
return throwError(() => error);
}
}),
}
private trySaveToken() {
this.http.post(this.authUrl).subscribe({
next: (response) => {
this.token = 'Bearer ' + response.data.access_token;
},
});
}
}
My retry logic might not be correct yet, but I can't really work on that until I get the first authorization issue solved first
here is what the console.log
produces
Object [AxiosHeaders] {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'User-Agent': 'axios/1.6.8',
'Content-Length': '162',
'Accept-Encoding': 'gzip, compress, deflate, br'
}
It turns out that I need to be setting the Authorization
header like this
this.http.axiosRef.defaults.headers.common.Authorization = this.token;
I do not fully understand why I have to do this, but it does work