angularazure-ad-msalangular-http-interceptorsmsal-angular

How to bypass MSAL interceptor conditionally in Angular


I have an application that so far uses username and password authentication to get a custom JWT token from the backend. Once I got the token, I use my custom interceptor to add it to the headers:

@Injectable()
export class JwtInterceptor implements HttpInterceptor {

  constructor(private authService: AuthService) {}

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    request = request.clone({
      setHeaders: {
        Authorization: `Bearer ${ this.authService.getToken()}`
      }
    });
    return next.handle(request);
  }
}

Now I want to use both: username/password and OAuth2 authentication using MSAL library. I have added and configured MSAL library to the app. I also have two interceptors defined in app.module.ts:

providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: JwtInterceptor,
    multi: true
  },
  {
    provide: HTTP_INTERCEPTORS,
    useClass: MsalInterceptor,
    multi: true
  }
]

Now when authenticating using username and password, MsalInterceptor is taking over the request and redirects me to Microsoft login page or injects MSAL token to the request.

My question is: how can I bypass MsalInterceptor conditionally, for example when custom JWT is already there? I tried to create another custom interceptor and use MsalInterceptor in the constructor, but I get circular dependency injection. Is there any solution to use only one out of two defined interceptors, based on some condition?


Solution

  • I managed to do this by subclassing the interceptor and adding code using a context token like this.

    export const BYPASS_MSAL = new HttpContextToken(() => false);
    
    @Injectable()
    export class MsalSkipInterceptor extends MsalInterceptor implements HttpInterceptor {
      intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
        if (request.context.get(BYPASS_MSAL)) {
          return next.handle(request);
        }
        return super.intercept(request, next);
      }
    }
    

    Then using this interceptor instead of the MsalInterceptor in your application you can skip a request by providing a context where you have set BYPASS_MSAL in the context to true.