Skip to content

Api Calls do not authenticate with Module Federation #7705

Open
@ZakAl-Hassani

Description

@ZakAl-Hassani

Core Library

MSAL.js (@azure/msal-browser)

Core Library Version

4.11.0

Wrapper Library

MSAL Angular (@azure/msal-angular)

Wrapper Library Version

4.0.10

Public or Confidential Client?

Public

Description

New angular application using Module Federation provides route guard using msal however any api calls return a 401 unauthorised error. When the same code is used in an angular application that does not use Module Federation, the route guard and the api calls authenticate as expected. I am using MSAL and angular 19 and have tried this a number of times (creating new applications each time). My application is authenticating using b2c.

Error Message

HttpErrorResponse {headers: _HttpHeaders, status: 401, statusText: 'OK', url: 'https://localhost:55001/WeatherForecast', ok: false, …}
error
:
null
headers
:
_HttpHeaders {headers: undefined, normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
message
:
"Http failure response for https://localhost:55001/WeatherForecast: 401 OK"
name
:
"HttpErrorResponse"
ok
:
false
status
:
401
statusText
:
"OK"
type
:
undefined
url
:
"https://localhost:55001/WeatherForecast"
[[Prototype]]
:
HttpResponseBase

MSAL Logs

No log is produced. A log is produced when not using Module Federation

Network Trace (Preferrably Fiddler)

  • Sent
  • Pending

MSAL Configuration

adb2cConfig: {
      logOutput: true,
      clientId: 'clientId',
      readScopeUrl: 'https://scpusers.onmicrosoft.com/weather/api/Weather.Read',
      writeScopeUrl: 'https://scpusers.onmicrosoft.com/weather/api/Weather.Write',
      apiEndpointUrls: [
        currentApiServerUrl + 'WeatherForecast'
      ],
      authorities: {
                signUpSignIn: {
                    authority: 'https://scpusers.b2clogin.com/scpusers.onmicrosoft.com/b2c_1_si'
                },
                resetPassword: {
                    authority: 'https://scpusers.b2clogin.com/scpusers.onmicrosoft.com/b2c_1_reset'
                },
                editProfile: {
                    authority: "https://scpusers.b2clogin.com/scpusers.onmicrosoft.com/b2c_1_edit"
                }
            }
    }

Relevant Code Snippets

import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core';
import { provideRouter, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation } from '@angular/router';
import { provideNoopAnimations } from '@angular/platform-browser/animations';

import { routes } from './app.routes';
import { BrowserCacheLocation, BrowserUtils, Configuration, InteractionType, IPublicClientApplication, LogLevel, PublicClientApplication } from '@azure/msal-browser';
import { environment } from '../environments/environment';
import { MSAL_GUARD_CONFIG, MSAL_INSTANCE, MSAL_INTERCEPTOR_CONFIG, MsalBroadcastService, MsalGuard, MsalGuardConfiguration, MsalInterceptor, MsalInterceptorConfiguration, MsalService, ProtectedResourceScopes } from '@azure/msal-angular';
import { BrowserModule } from '@angular/platform-browser';
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';



const isIE = window.navigator.userAgent.indexOf("MSIE ") > -1 || window.navigator.userAgent.indexOf("Trident/") > -1;

export const b2cPolicies = {
  names: {
    signUpSignIn: 'B2C_1_si',
    resetPassword: 'B2C_1_reset',
    editProfile: 'B2C_1_edit',
  },
  authorities: {
    signUpSignIn: {
      authority: 'https://scpusers.b2clogin.com/scpusers.onmicrosoft.com/B2C_1_si',
    },
    resetPassword: {
      authority: 'https://scpusers.b2clogin.com/scpusers.onmicrosoft.com/B2C_1_reset',
    },
    editProfile: {
      authority: 'https://scpusers.b2clogin.com/scpusers.onmicrosoft.com/B2C_1_edit',
    },
  },
  authorityDomain: 'scpusers.b2clogin.com',
};

export const msalConfig: Configuration = {
  auth: {
    clientId: environment.adb2cConfig.clientId, // This is the ONLY mandatory field that you need to supply.
    authority: b2cPolicies.authorities.signUpSignIn.authority, // Defaults to "https://login.microsoftonline.com/common"
    knownAuthorities: [b2cPolicies.authorityDomain], // Mark your B2C tenant's domain as trusted.
    redirectUri: '/', // Points to window.location.origin by default. You must register this URI on Azure portal/App Registration.
    postLogoutRedirectUri: '/', // Points to window.location.origin by default.
  },
  cache: {
    cacheLocation: BrowserCacheLocation.LocalStorage, // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs.
    storeAuthStateInCookie: isIE, // Set this to "true" if you are having issues on IE11 or Edge. Remove this line to use Angular Universal
  },
  system: {
    /**
     * Below you can configure MSAL.js logs. For more information, visit:
     * https://docs.microsoft.com/azure/active-directory/develop/msal-logging-js
     */
    loggerOptions: {
      loggerCallback(logLevel: LogLevel, message: string) {
        if (environment.adb2cConfig.logOutput) {
          console.log(message);
        }
      },
      logLevel: LogLevel.Verbose,
      piiLoggingEnabled: false
    }
  }
}

export const loginRequest = {
  scopes: []
};


export function MSALInstanceFactory(): IPublicClientApplication {
  return new PublicClientApplication(msalConfig);
}

export function MSALGuardConfigFactory(): MsalGuardConfiguration {
  return {
    interactionType: InteractionType.Redirect,
    authRequest: loginRequest
  };
}


export function protectedResources(): any[] {
  let ret: any[] = [];

  environment.adb2cConfig.apiEndpointUrls.forEach(endpoint => {
    let api = {
      api: {
        endpoint: endpoint,
        scopes: {
          read: [environment.adb2cConfig.readScopeUrl],
          write: [environment.adb2cConfig.writeScopeUrl]
        }
      }
    };
    ret.push(api);
  });

  return ret;
}

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {

  const protectedResourceMap = new Map<string, Array<string | ProtectedResourceScopes> | null>();

  protectedResources().forEach(resource => {
    protectedResourceMap.set(resource.api.endpoint, [
          {
      httpMethod: 'GET',
      scopes: [...resource.api.scopes.read]
    },
    {
      httpMethod: 'POST',
      scopes: [...resource.api.scopes.write]
    },
    {
      httpMethod: 'PUT',
      scopes: [...resource.api.scopes.write]
    },
    {
      httpMethod: 'PATCH',
      scopes: [...resource.api.scopes.write]
    },
    {
      httpMethod: 'DELETE',
      scopes: [...resource.api.scopes.write]
    }
    ]);
  });

  return {
    interactionType: InteractionType.Redirect,
    protectedResourceMap
  };
}

const initialNavigation = !BrowserUtils.isInIframe() && !BrowserUtils.isInPopup()
  ? withEnabledBlockingInitialNavigation() // Set to enabledBlocking to use Angular Universal
  : withDisabledInitialNavigation();


export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }), 
    provideRouter(routes, initialNavigation),
    importProvidersFrom(BrowserModule),
    provideNoopAnimations(),
    provideHttpClient(withInterceptorsFromDi()),
    {
      provide: HTTP_INTERCEPTORS,
      useClass: MsalInterceptor,
      multi: true
    },
    {
      provide: MSAL_INSTANCE,
      useFactory: MSALInstanceFactory
    },
    {
      provide: MSAL_GUARD_CONFIG,
      useFactory: MSALGuardConfigFactory
    },
    {
      provide: MSAL_INTERCEPTOR_CONFIG,
      useFactory: MSALInterceptorConfigFactory
    },
    MsalService,
    MsalGuard,
    MsalBroadcastService
  ]
};

Reproduction Steps

  1. Create new angular workspace.
  2. Add shell application
  3. Install native federation npm i @angular-architects/native-federation -D
  4. Activate native federation for each application
  5. Configure project for MSAL using an existing configuration that works in projects that do not use Module Federation
  6. Log in to http://localhost:4200
  7. Access page that makes call to b2c protected api (which normally works in non Module Federation project)

Expected Behavior

A 200 Ok success with weather forecast results is returned from Api call

Identity Provider

Azure B2C Basic Policy

Browsers Affected (Select all that apply)

Chrome, Edge

Regression

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Author FeedbackAwaiting response from issue authorb2cRelated to Azure B2C library-specific issuesbug-unconfirmedA reported bug that needs to be investigated and confirmedmsal-angularRelated to @azure/msal-angular packagemsal-browserRelated to msal-browser packagepublic-clientIssues regarding PublicClientApplicationsquestionCustomer is asking for a clarification, use case or information.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions