Angular Web Component http calls are not routing through clients http interceptor

Viewed 508

Set-up:

I have a web component (Angular 10) being used in an Angular 10 Application. The web component makes an Httpclient call to a web API to get some data to populate a menu dropdown. The web component was made using the standard methods to make a web component using Angular 10.

The web component is loaded through a script in the main client application. This is from the angular.json file for the parent application.

1."scripts":
 [
    "projects/web-component-test/src/assets/plugin.bundle.js"
 ]

and all works fine except we get a 401 error (unauthorized) since the end point requires the user to be logged in. By working fine, there are other controls that display as required just the the dropdown list, which gets it data from the API call does not get populated.

The flow:

  1. User goes to website and then is prompted to log in (using keycloak Auth).
  2. Application loads fine, except for the 401 error when the web component tries to load the menu items.

Http calls from the parent app work fine; the jwt token is added to the header for the call to the protected API. Calls from the child web component do not have the jwt token in the header, and thus fail with a 401 error.

httpinterceptor: we have an httpinterecptor on the main client application (the parent of the web control). Http calls that are made from the main app are routed through the interceptor where the token is attached to the header if needed.

Calls made from the child Web Component DO NOT hit the interceptor in the parent app?

Question: How do I make call from the child web component route through the http interceptor in the parent so the token can be added.

Things I have tried: I can get the web component to work fine if I do this:

  1. When the parent loads I store the token in local storage
  2. using an http interceptor on the web component, retrieve the token from local storage and use it.

** works, but I DO NOT want to store a secure token in local storage.

Pass the token in an attribute on the child component when the parent loads the child component

** again, I can get it to work, but not very secure.

1 Answers

A web component is an independent piece of code from your main codebase, so when you hit a request from the web component, your main app won't be able to catch those requests in the interceptor.

For me, one thing it worked was creating different Custom Events per every request:

  • doGetRequest
  • doPostRequest
  • doPutRequest
  • doDeleteRequest

Let me quickly guide you through one example of these events.

From the main app, I'm listening if any of these events are triggered:

this.popupEl.addEventListener('doPostRequest', (info: HTMLElementEventMap | any) => {
            this.performHttpRequest(info.detail);
        });

Notice that all the info sent from your web component, can be found in the property 'detail' your main app receives.

From the web component, I execute the following:

this.doPostRequest.emit({
            url: 'the URL to hit',
            endpointParams: {
                user: 'my user',
                password: '******',
            }
        });

Note: You can change the structure of the params to sent. It's totally up to you.

This will trigger the execution of the API in the main app, and as the request was executed from the main app, your interceptor will do its work and add whatever JWT you have there. Once the main app receives the response, you will need to set a new property in your web component to pass the response to it. Something like this:

this.popupEl.apiResponse = {
                webComponentInfo: { ...infoReceivedFromYourWebComponent },
                apiDetails: { ...ResponseFromYourBackend}
            };

Finally, in your web component, add a new input that listen for the apiResponse attribute:

@Input()
    set apiResponse(apiResponse: RequestParams) {
        if (apiResponse.webComponentInfo.url === 'the URL to hit') {
            // Do what you want in your web component, as you know exactly which URL just got executed.
        }
    }

This way, you let your main app continue doing its work with your interceptor and the web component won't need to handle the JWT or actually perform the requests. One thing you may want to consider is not allowing the Delete request from your web component unless you and only you have full control over the web component. You wouldn't want anything that can perform a successful DELETE request to a very important API.

Hope this helps.

Related