microsoft-authentication-library-for-js icon indicating copy to clipboard operation
microsoft-authentication-library-for-js copied to clipboard

Observable fro msalBroadcastService doesn't send all InteractionStatus or Event

Open 0xdbe opened this issue 3 years ago • 16 comments

Core Library

MSAL.js v2 (@azure/msal-browser)

Core Library Version

2.18.0

Wrapper Library

MSAL Angular (@azure/msal-angular)

Wrapper Library Version

2.0.4

Description

Since msal-angular 2.0.3, Observables from msalBroadcastService doesn't send all data:

  • inProgress$: missing some InteractionStatus such as none. I receive only startup
  • msalSubject$: missing some EventMessage such as handleRedirectStart. I receive some other likehandleRedirectEnd

Error Message

No response

Msal Logs

3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - MsalRedirectComponent activated' msalInstance.factory.ts:8 
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - handleRedirectPromise called' msalInstance.factory.ts:8
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - getAllAccounts called' msalInstance.factory.ts:8 
2 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectStart' msalInstance.factory.ts:8 
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - handleRedirectPromise has been called for the first time, storing the promise' msalInstance.factory.ts:8 
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : [5fc57d40-0f7c-41a6-bf5c-b1cca863e9a4] : [email protected] : Verbose - initializeServerTelemetryManager called' msalInstance.factory.ts:8 
2 '[Wed, 20 Oct 2021 16:11:21 GMT] : [5fc57d40-0f7c-41a6-bf5c-b1cca863e9a4] : [email protected] : Info - handleRedirectPromise called but there is no interaction in progress, returning null.' core.js:28039 
Angular is running in development mode. Call enableProdMode() to enable production mode. msalInstance.factory.ts:8 
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - Event callback registered with id: fd4aeb5a-9e1b-45ea-b685-3f9c66bbfbf6' msalInstance.factory.ts:8 
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - getAllAccounts called' auth.service.ts:31 
MSAL Interaction Status: startup msalInstance.factory.ts:8 
2 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectEnd' msalInstance.factory.ts:8 
3 '[Wed, 20 Oct 2021 16:11:21 GMT] : @azure/[email protected] : Verbose - Emitting event to callback fd4aeb5a-9e1b-45ea-b685-3f9c66bbfbf6: msal:handleRedirectEnd'
auth.service.ts:45 
MSAL Event Type: msal:handleRedirectEnd index.js:52
[WDS] Live Reloading enabled.

MSAL Configuration

export function MSALInstanceFactory(): IPublicClientApplication {
  return new PublicClientApplication({
    auth: {
      clientId: environment.aad.clientId,
      authority: 'https://login.microsoftonline.com/' + environment.aad.tenantId,
      redirectUri: environment.aad.redirectUri,
      postLogoutRedirectUri: '/',
      navigateToLoginRequestUrl: true
    },
    cache: {
      cacheLocation: 'sessionStorage',
      storeAuthStateInCookie: false
    },
    system: {
      loggerOptions: {
        loggerCallback,
        logLevel: LogLevel.Verbose,
        piiLoggingEnabled: false
      }
    }
  });
}

Relevant Code Snippets

// inProgress Observble
this.msalBroadcastService.inProgress$.subscribe({
  next: (status: InteractionStatus) => {
    if (environment.debug.msal) {
      console.log(`MSAL Interaction Status: ${status}`);
    }
  }
});

// msalSubject observable
this.msalBroadcastService.msalSubject$.subscribe({
  next: (event: EventMessage) => {
    if (environment.debug.msal) {
      console.log(`MSAL Event Type: ${event.eventType}`);
    }
  }
});

Reproduction Steps

  1. Clone https://github.com/0xdbe-example/angular-msal-azure-ad
  2. Configure Azure AD and MSAL (in environment file)
  3. Run with ng serve (needs mkcert for HTTPS)
  4. Open your browser, authentication should works
  5. Update MSAL and restart
  6. Open your browser, authentication doesn't work anymore.

Expected Behavior

  • inProgress$: must send all InteractionStatus including none
  • msalSubject$: must send all EventMessage including handleRedirectStart

Identity Provider

Azure AD / MSA

Browsers Affected (Select all that apply)

Chrome

Regression

@azure/msal-angular 2.0.1 with @azure/msal-browser 2.16.1

Source

External (Customer)

0xdbe avatar Oct 20 '21 16:10 0xdbe

@0xdbe Thanks for the information. Did you try debugging MSAL Angular or MSAL Browser to see what is happening? Are the events being emitted from MSAL Browser but dropped by MSAL Angular, or not getting emitted by MSAL Browser at all?

jasonnutter avatar Oct 20 '21 22:10 jasonnutter

@jasonnutter:

Here, verbose log with @azure/msal-angular v2.0.4:

Navigated to https://localhost:4200/
core.js:28039 Angular is running in development mode. Call enableProdMode() to enable production mode. msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - MsalRedirectComponent activated' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - handleRedirectPromise called' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - getAllAccounts called' msalInstance.factory.ts:9 
2 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectStart' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - handleRedirectPromise has been called for the first time, storing the promise' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : [d2ab448f-f2c7-412d-b067-ebd3a03d458b] : [email protected] : Verbose - initializeServerTelemetryManager called' msalInstance.factory.ts:9 
2 '[Tue, 26 Oct 2021 14:12:47 GMT] : [d2ab448f-f2c7-412d-b067-ebd3a03d458b] : [email protected] : Info - handleRedirectPromise called but there is no interaction in progress, returning null.' core.js:28039 
Angular is running in development mode. Call enableProdMode() to enable production mode. msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - Event callback registered with id: b9e13b68-a36a-4fad-8fd9-acca84c176ae' msalInstance.factory.ts:9
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - getAllAccounts called' auth.service.ts:31 
MSAL Interaction Status: startup msalInstance.factory.ts:9 
2 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectEnd' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:12:47 GMT] : @azure/[email protected] : Verbose - Emitting event to callback b9e13b68-a36a-4fad-8fd9-acca84c176ae: msal:handleRedirectEnd' auth.service.ts:45 
MSAL Event Type: msal:handleRedirectEnd index.js:52 
[WDS] Live Reloading enabled.

And now log with @azure/msal-angular v2.0.1 and msal-browser v2.18.0:

Navigated to https://localhost:4200/
core.js:28047 Angular is running in development mode. Call enableProdMode() to enable production mode. msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - MsalRedirectComponent activated' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - handleRedirectPromise called' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - getAllAccounts called' msalInstance.factory.ts:9 
2 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectStart' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - handleRedirectPromise has been called for the first time, storing the promise' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : [ddde7be9-eca5-4e56-8af3-03d3ce16255a] : [email protected] : Verbose - initializeServerTelemetryManager called' msalInstance.factory.ts:9 
2 '[Tue, 26 Oct 2021 14:23:19 GMT] : [ddde7be9-eca5-4e56-8af3-03d3ce16255a] : [email protected] : Info - handleRedirectPromise called but there is no interaction in progress, returning null.' core.js:28047 
Angular is running in development mode. Call enableProdMode() to enable production mode. msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - Event callback registered with id: 781dd2ff-9b02-4ff5-83c5-e0f235a3612d' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - getAllAccounts called' auth.service.ts:31 
MSAL Interaction Status: startup msalInstance.factory.ts:9 
2 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Info - Emitting event: msal:handleRedirectEnd' msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - Emitting event to callback 781dd2ff-9b02-4ff5-83c5-e0f235a3612d: msal:handleRedirectEnd' auth.service.ts:45 
MSAL Event Type: msal:handleRedirectEnd msalInstance.factory.ts:9 
3 '[Tue, 26 Oct 2021 14:23:19 GMT] : @azure/[email protected] : Verbose - BroadcastService - msal:handleRedirectEnd results in setting inProgress to none' auth.service.ts:31 
MSAL Interaction Status: none auth.service.ts:129 
BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
index.js:52 [WDS] Live Reloading enabled.

As you can see, with MSAL angular v2.01, I receive events from BroadcastService.

To understand what happens in my prototype, I decide to test the angular official sample app with @azure/msal-angular v2.0.4 => I receive all events from BroadcastService !

The difference between my prototype and the sample app:

  • In my prototype, the subscription to BroadcastService observable is in auth.service.ts (a service, not a component).
  • In your angular example, the subscription to BroadcastService observable is in app root component.

So, I found a workaround: add msalBroadcastService in app component constructor !

export class AppComponent {

  constructor(
    private msalBroadcastService: MsalBroadcastService
  ) {}

It works but I don't understand why it is needed to inject MsalBroadcastService in the root component. The MsalBroadcastService is already in providers list (in app root module).

0xdbe avatar Oct 26 '21 14:10 0xdbe

I update my project to use @azure/[email protected]: https://github.com/0xdbe-example/angular-msal-azure-ad/commit/a692420ec4fc8cea574189b7b50cf1d94d481ba3

It works but MsalBroadcastService is injected in app component constructor (without subscription). I don't know why is needed.

0xdbe avatar Oct 26 '21 15:10 0xdbe

@0xdbe Interesting, thanks for the update. I wonder if this is timing-related (i.e. the required event listener isn't registered in time to capture certain events from MSAL)?

jasonnutter avatar Oct 26 '21 20:10 jasonnutter

How can I check that?

0xdbe avatar Oct 26 '21 20:10 0xdbe

You can try debugging the emitEvent function and seeing if event listeners are registered when teh events you are missing are emitted: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/310c2b33484650689e949e72d56e778af76265d9/lib/msal-browser/src/event/EventHandler.ts#L104

jasonnutter avatar Oct 27 '21 17:10 jasonnutter

Indeed, it could be timing-related.

Execution Flow

Step 1

MsalRedirectComponent is firstly loaded. It seems normal since this component is defined in module bootstrap.

This component emits a new event: msal:handleRedirectStart. But MsalBroadcastService can't take into consideration this event because this service is yet loaded

Step 2

MsalBroadcastService starts and runs the following actions:

  • Init inProgress$ observable to InteractionStatus.Startup
  • Register event callback

Step 3

MsalRedirectComponent sends new event msal:handleRedirectEnd.

MsalBroadcastService receives this event and tries to define the status:

const status = EventMessageUtils.getInteractionStatusFromEvent(EventMessage, currentStatus);

where:

  • EventMessage.eventType = handleRedirectEnd
  • currentStatus = startup

getInteractionStatusFromEvent returns null because:

case EventType.HANDLE_REDIRECT_END:
    if (currentStatus && currentStatus !== InteractionStatus.HandleRedirect) {
        // Prevent this event from clearing any status other than handleRedirect
        break;
    }
    return InteractionStatus.None;

So, status will never set to InteractionStatus.None

Origin

Previously, getInteractionStatusFromEvent takes only EventMessage to define status

since this commit https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/2d8898a9e87b5844d6b4b7ed7c9ebfdaf6bc7491# getInteractionStatusFromEvent takes EventMessage AND currentStatus.

Workaround

Start MsalBroadcastService before MsalRedirectComponent, such as in appComponent.

Fix

  • Inject MsalBroadcastService in MsalRedirectComponent ?
  • update getInteractionStatusFromEvent ?

0xdbe avatar Oct 28 '21 11:10 0xdbe

This issue requires attention from the MSAL.js team and has not seen activity in 5 days. @jasonnutter please follow up.

ghost avatar Nov 03 '21 01:11 ghost

@0xdbe Thank you for the details. We'll add this to our backlog as a potential enhancement.

jasonnutter avatar Nov 03 '21 16:11 jasonnutter

@0xdbe Curious if the changes made in #4998 help here?

jasonnutter avatar Jul 28 '22 17:07 jasonnutter

Any updates?

Still reproducing with Angular v14 and "@azure/msal-angular": "^2.5.5", "@azure/msal-browser": "^2.35.0". If I don't inject private msalBroadcastService: MsalBroadcastService in my auth.service.ts, I'm unable to login/logout.

seerj30 avatar Apr 19 '23 12:04 seerj30

This issue still exists. I'm getting only 'Startup' interaction status and couldn't get status as 'None'. Any permanent fix for this issue would be really helpful.

aravind74 avatar May 02 '23 04:05 aravind74

I used APP_INITIALIZER for the redirect handling. It works only when I include MsalBroadcastService as a dependency:

{
  provide: APP_INITIALIZER,
  useFactory: (authService: MsalService) => () => authService.handleRedirectObservable(),
  deps: [MsalService, MsalBroadcastService],
  multi: true
},

Otherwise I get startup when the Interceptor tries to refresh the token.

ckorherr avatar Jul 30 '23 19:07 ckorherr

Finally found this issue, and while I am very happy for the workaround, it is also very frustrating that they needed to be imported in a specific order.

For us, it caused redirect logins not to work as fallback in the angular intercetpr (because state was never emitted properly).

submarines-and avatar Aug 03 '23 05:08 submarines-and

I used APP_INITIALIZER for the redirect handling. It works only when I include MsalBroadcastService as a dependency:

{
  provide: APP_INITIALIZER,
  useFactory: (authService: MsalService) => () => authService.handleRedirectObservable(),
  deps: [MsalService, MsalBroadcastService],
  multi: true
},

Otherwise I get startup when the Interceptor tries to refresh the token.

This fixed it for me. The problem originally started after migrating to use standalone components.

strauss02 avatar Aug 03 '23 07:08 strauss02

Any updates on this?

seerj30 avatar Mar 11 '24 09:03 seerj30