How to authenticate a Teams tab app built in Angular using Microsoft Entra

24 Views Asked by At

I’m working on developing a Teams tab app in Angular. I’m stuck at the authentication process. To summarize the problem, the Angular app itself is working fine and the authentication using Entra is working fine in the web app. I tried using loginPopup and loginRedirect from MsalService on the web app and that works without a problem.

In the Teams app instead, I’m initializing the app in the app.component.ts file using app.initialize(). I’m using authentication.authenticate() from @microsoft/teams-js.

I'm using @azure/msal-angular (3.0.12), @azure/msal-browser (3.9.0) and @microsoft/teams-js (2.20.0).

 authentication.authenticate({ 
      url: window.location.origin + "/auth-start", 
      width: 600, 
      height: 535 
    }) 
      .then((result) => { 
        console.log("Login succeeded: " + result); 
      }) 
      .catch((reason) => { 
        console.log("Login failed: " + reason); 
      }); 

Here's auth-start

ngOnInit(): void { 
    this.msalService.handleRedirectObservable().subscribe(); 
    app.getContext().then(async (context) => { 
      this.loginRedirect(context.user?.loginHint); 
    }); 
  } 

  loginRedirect(loginHint?: string) { 
      let req = { ...this.msalGuardConfig.authRequest } as RedirectRequest; 
      req.loginHint = loginHint; 
      req.redirectUri = window.location.origin + `/auth-end`; 
      this.msalService.loginRedirect(req); 
  } 

Here’s auth-end:

  ngOnInit(): void { 
      app.getContext().then(async (context) => { 
        await this.msalInstance.initialize(); 

        await this.msalInstance.handleRedirectPromise() 
          .then((tokenResponse) => { 
            if (tokenResponse !== null) { 
              authentication.notifySuccess(JSON.stringify(tokenResponse)); 
            } else { 
              authentication.notifyFailure("Get empty response."); 
            } 
          }) 
          .catch((error) => { 
            authentication.notifyFailure(JSON.stringify(error)); 
          }); 
      }); 
  } 

After the authentication process, the code reaches authentication.notifySuccess, it returns the correct tokenResponse from auth-end and the popup closes as expected.

Then the problem starts. After the popup closes, the main app is supposed to authenticate but it doesn’t do anything. I tried authenticating it manually using msalService.instance.setActiveAccount() but with no success.

Here’s my app configuration which is authenticating correctly for the website but not the Teams app:

export function MSALInstanceFactory(): IPublicClientApplication {
  return new PublicClientApplication({
    auth: {
      clientId: environment.msalConfig.auth.clientId,
      authority: environment.msalConfig.auth.authority,
      redirectUri: '/',
      postLogoutRedirectUri: '/',
      navigateToLoginRequestUrl: false
    },
    cache: {
      cacheLocation: BrowserCacheLocation.SessionStorage
    },
    system: {
      allowNativeBroker: false, // Disables WAM Broker
      loggerOptions: {
        loggerCallback,
        logLevel: LogLevel.Info,
        piiLoggingEnabled: false
      }
    }
  });
}

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
  const protectedResourceMap = new Map<string, Array<string>>([
    [environment.graphConfig.uri, environment.graphConfig.scopes],
    [environment.apiUrl, environment.apiScopes]
  ]);

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

export function MSALGuardConfigFactory(): MsalGuardConfiguration {
  return {
    interactionType: InteractionType.Redirect,
    authRequest: {
      scopes: [...environment.graphConfig.scopes]
    },
    loginFailedRoute: '/login-failed'
  };
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideClientHydration(),
    provideAnimationsAsync(),
    provideHttpClient(withInterceptors([errorInterceptor]), 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,
    { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } },
    provideNativeDateAdapter(),
    { provide: MAT_DATE_LOCALE, useValue: 'en-GB' }
  ]
};

In my testing, I’ve found that the popup itself gets authenticated as it shows the component guarded by MsalGuard when the authentication process is complete, but after it is closed, the main app stays unauthenticated.

0

There are 0 best solutions below