angulartypescriptjwtprogressive-web-appsmean-stack

Angular HTTP interceptor not modifying HTTP request headers


I am working with Angular 13, attempting to add a JWT to headers to access a restricted route on the backend. Upon backend inspection JwtInterceptor does not appear to modify the HTTP request headers. I've only included HttpClientModule once in my project, in the root AppModule. I've appended a pipe function with error catching to my next object (inside of interceptor) in an effort to debug as suggested by someone with a similar issue on SO to no avail, removed pipe funct for brevity.

I've gone as basic as console.log'ing within the file but there was no output to account for it so I suspect the interceptor isn't firing at all.

I've worked with interceptors before and haven't had this issue so I'm stumped. The only difference here is that I'm working with an Angular PWA, if I understand correctly a service worker is not supposed to hinder the behavior of an interceptor? I understood that a POST request would fall under a "cache busting" event?

Maybe the error is in the implementation of the PWA? I did follow the docs in this case.

Attached are the App Module, Jwtinterceptor and "Barrel" of HttpInterceptors, I'm planning on adding more interceptors to project so I followed the docs suggestion and created the Barrel.

TL;DR
My HttpInterceptor (JwtInterceptor) does not appear to be firing at all. This implementation has worked for me in past projects, only difference is this project is a PWA. Not sure if it's a conflict or quirk with PWA implementation. HttpClientModule is included only once in project.

app.module.ts

//Angular level imports
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

//App level components
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { HeaderComponent } from './header/header.component';
import { AngularMaterialModule } from './_material/material.module';
import { UploadDirective } from './directives/upload.directive';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { ThanksComponent } from './thanks/thanks.component';
import { PhotoAlbumsComponent } from './photo-albums/photo-albums.component';
import { DialogComponent } from './dialog/dialog.component';
import { AlbumComponent } from './album/album.component';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { ForgotPasswordComponent } from './forgot-password/forgot-password.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component';
import { ThanksBotDownloadComponent } from './thanks-bot-download/thanks-bot-download.component';
import { ErrorBotDownloadComponent } from './error-bot-download/error-bot-download.component';
import { RouterModule } from '@angular/router';
import { httpInterceptorProviders } from './_interceptors/index';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    HeaderComponent,
    UploadDirective,
    LoginComponent,
    RegisterComponent,
    ThanksComponent,
    PhotoAlbumsComponent,
    AlbumComponent,
    DialogComponent,
    ForgotPasswordComponent,
    ResetPasswordComponent,
    ThanksBotDownloadComponent,
    ErrorBotDownloadComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    FormsModule,
    ReactiveFormsModule,
    AngularMaterialModule,
    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled: environment.production,
      // Register the ServiceWorker as soon as the app is stable
      // or after 30 seconds (whichever comes first).
      registrationStrategy: 'registerWhenStable:30000',
    }),
    HttpClientModule,
    RouterModule,
  ],
  providers: [httpInterceptorProviders],
  bootstrap: [AppComponent],
})
export class AppModule {}

jwt.interceptor.ts

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { environment } from '@environments/environment';
import { AccountService } from '@app/_services/account.service';


@Injectable()
export class JwtInterceptor implements HttpInterceptor {
  constructor(private accountService: AccountService) {}

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    // add auth header with jwt if user is logged in and request is to the api url
    //console.log("JWT Interceptor");
    const user = this.accountService.currentUserValue;
    const isLoggedIn = user && user.jwt;
    const isApiUrl = request.url.startsWith(environment.apiUrl);
    if (isLoggedIn && isApiUrl) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${user.jwt}`,
        },
      });
    }

    return next.handle(request);
  }
}

index.ts "Barrel" file

/* "Barrel" of Http interceptors */
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { JwtInterceptor } from './jwt.interceptor';

/* Http interceptor providers in outside-in order */
export const httpInterceptorProviders = [
  { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
];

Post request Headers Request Headers on backend


Solution

  • Instead of setHeaders try headers.

    request = req.clone({
        headers: req.headers.append('Authorization', `Bearer ${user.jwt}`)
    });
    

    Though it seems this issue is caused by your condition not being met.