2

Following software architecture: enter image description here

Architecture:
There is one Microfrontend (MFE) which should be integrated in two different shells (Shell 1 & Shell 2).
Each Shell for itself can consist out of only the MFE or several other components.
Each Shell and the MFE itself can have access to individual REST-APIs which secured with an Access-Token

Authorization
Shell 1 and Shell 2 are secured via an Authorization through Keycloak Identify Provider.
If User access Shell 1 or Shell 2 and does not have a valid access token, it is redirected to a login-page. After successful login the User gets redirected to the Shell Application.

Problem
The Microfrontend (MFE) itself needs to be secured also via an separate Access-Token, which will be used then for the communication towards the REST-API. At the moment when integrating the Microfrontend into the Shell an "Authorization Issue" occurs because the Shell Token which is used is not valid for the Microfrontend.

Question
What options are possible to achieve following:

  • User A logins to Shell A with User Token for Shell A
  • For Shell A the Mircofrontend will be integrated (Shell integrates / calls the Mircofrontend with the relevant Mircofrontend Token) and can use the Microfrontend.
  • If User B calls Mircofrontend directly he needs to authorize via an individual Mircofrontend User Token.
  • If User C calls Shell B and logs in with User Token for Shell B, similar behaviour then for Shell A

Additional Information
Shells and Microfrontend are implemented in Angular using Angular Module Federation.
As Identity Provider Keycloak is used without Token-Exchange.

BigTman
  • 142
  • 6

1 Answers1

0

I bring you the workaround we've come up. Currently with my team we're using Angular Module Federation with Web Components, following this article and the whole series.

Our versions are: Angular 14, keycloak-angular 6 and keycloak-js 4 (a little bit too old, but expecting to update soon).

We saw that module-federation-tools package uses a WebComponentWrapper component in the shell in order to load the remote, so we created our own kind of copy because we wanted to redirect to a custom error page if the load failed.

Following the this.element[prop] = this.props[prop]; pattern the component uses, we did pass a Store: a service we created to share some props, like the token for example.

// keycloak.loader --> factory method used in AppModule providers
keycloakInitializer(keycloak: KeycloakService, storeService: StoreService): () => Promise<any> {

    await keycloak.init({...}) // skip details to be brief about the implementation

    storeService.setToken({
        token: keycloak.getKeycloakInstance().token!,
        refreshToken: keycloak.getKeycloakInstance().refreshToken!
    })
}

// custom-wrapper.ts
constructor(public store: StoreService) { }

ngAfterContentInit() {
...
// Load remote module with MFE-related options 
element['store'] = this.store;
// set additional attributes to element if necessary and apply ElementRef.appendChild() as stated in web-component-wrapper.ts by Angular Architects
...

On the other side, the AppComponent on the remote has an @Input() store: StoreService and with the token received in there, handles the KeycloakService initialization (keycloakService.init() method).

// app-component.ts
@Input('store') store?: Store;

constructor(private keycloakService: KeycloakService) {}

ngOnInit() {
    if (this.store) {
        initOptions = {
            token: this.store.getTokenCurrent().token,
            refreshToken: this.store.getTokenCurrent().refreshToken
            // other options used to initialize KC
            ...
        }
    }

    this.keycloakService.init(initOptions);
}

This worked for us using the Shell with the Remote together, but currently we're having a weird issue with this implementation:

  • Using the remote alone, it makes a strange redirection between our init page and the keycloak SSO. After a few redirections, finally the start page is shown and the app continues to work as expected.

Currently our MFE is quite related to our shell so it is not used in isolation (yet). We've been researching a lot to get rid of that weird behaviour with no much success, so if you have found any other solution, I would be glad to read it :)