How to configure Angular v15.2 standalone application with MSAL
Asked Answered
O

3

5

Before in ngModule base angular application you use to add MsalRedirectComponent in the bootstrap property of AppModule :

bootstrap: [AppComponent, MsalRedirectComponent]

Now in V15.2 the AppModule have been replace by the boostrapApplication function in main.ts :

bootstrapApplication(AppComponent, {
    providers: [
        importProvidersFrom(
            BrowserModule,
            AppRoutingModule,
           ),       
        provideAnimations(),
        provideHttpClient(withInterceptorsFromDi())
    ]
})
    .catch(err => console.error(err));

How to add the MsalRedirectComponent bootstrap ?

I try to add an other call after the first :

bootstrapApplication(MsalRedirectComponent, {
    providers: [
        importProvidersFrom(
            BrowserModule,
            AppRoutingModule,),
        provideHttpClient(withInterceptorsFromDi())
    ]
})
    .catch(err => console.error(err));

But this didn't work, the redirect didn't fired.

Otter answered 14/3, 2023 at 10:51 Comment(0)
O
4

For information, i post my working solution : I decide to not use the extends class, instead i use the handleRedirectObservable build in Msal property.

In main.ts I add the router for auth:

bootstrapApplication(AppComponent, {

    providers: [
         provideRouter([{ path: 'auth', loadComponent: () => import('@azure/msal-angular').then(mod => mod.MsalRedirectComponent) }]),

        importProvidersFrom(
            BrowserModule,
            AppRoutingModule,
           ),       
        provideAnimations(),
        provideHttpClient(withInterceptorsFromDi())
    ]
})
    .catch(err => console.error(err));

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styles: [],
  standalone: true,
  imports: [CommonModule,RouterOutlet]
})
export class AppComponent implements OnInit, OnDestroy {

  constructor(  
    private msalService: MsalService,
  ) {
     }

  ngOnInit(): void {
      this.msalService.handleRedirectObservable().subscribe();
  }
}
Otter answered 15/3, 2023 at 16:2 Comment(3)
For me this solution helped except I didn't add the 'auth' in the provedRouter and I didn't subscribe to the handleRedirect in the app component, instead in the service. handleRedirect$: Observable<AuthenticationResult> = this.msalService.handleRedirectObservable(); And then in the ngOnInit() { this.handleRedirect$.pipe(takeUntil(this._destroying$)).subscribe(); }Bhili
I used auth because i prefered to separate the auth callback from the 'real' routes navigation. For the handleRedirect, msalService is already a service, so I didn't see the use of re-wraped it in a service for only a single observable.Otter
For me it did not work. :(Dropsy
C
7

MSAL now officially supports Standalone components:

bootstrapApplication(AppComponent, {
    providers: [
        ...
        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
    ]
})

See the docs: https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-angular-v3-samples/angular-standalone-sample

Cuneal answered 29/8, 2023 at 18:0 Comment(1)
Don't forget to add this.authService.handleRedirectObservable().subscribe(); in app.component.ts on NgInitOtter
H
4

I'm not working with MsalRedirectComponent but it is a normal Component which manage redirects. Try extends on your app.component like this:

export class AppComponent extends MsalRedirectComponent {
  // Normal code....
}

The ngOnInit will be called in the MsalRedirectComponent. I hope it helps.

If you need it you can override it inside your AppCompnent

//...
override ngOnInit(): void {
  super.ngOnInit();
  // Your stuff
}
//...

Update

I have test it (with other components) and multiple call bootstrapApplication will work. You need to set the entry point in your index.html like this:

</head>
<body>
  <app-root></app-root>
  <app-redirect></app-redirect>
</body>
</html>

Then it should work.

Note NgModules are not "removed"! Standalone Components are only a new alternative to NgModules. So you can work with it!

Hargis answered 14/3, 2023 at 19:9 Comment(4)
Thx it's working, but it's not the most intuitive way... before : a simple array, after : extends a class and override methods...Otter
Question : How the angular cli know witch selector to use (app-root or app-redirect), we extends the base class (MsalRedirectComponent) and all two have a différent selector ?Otter
the app-root is the name of the Components selector (App.Component) and the app-redirect its the name of the MsalRedirectComponent (see in Github). If you change the name in the html as example you will see an error in the browsers console.Hargis
This helped me at first but then I changed it to the accepted answer, bcs this approach creates 2x app-root. You can check when in Angular Develop tools.Bhili
O
4

For information, i post my working solution : I decide to not use the extends class, instead i use the handleRedirectObservable build in Msal property.

In main.ts I add the router for auth:

bootstrapApplication(AppComponent, {

    providers: [
         provideRouter([{ path: 'auth', loadComponent: () => import('@azure/msal-angular').then(mod => mod.MsalRedirectComponent) }]),

        importProvidersFrom(
            BrowserModule,
            AppRoutingModule,
           ),       
        provideAnimations(),
        provideHttpClient(withInterceptorsFromDi())
    ]
})
    .catch(err => console.error(err));

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styles: [],
  standalone: true,
  imports: [CommonModule,RouterOutlet]
})
export class AppComponent implements OnInit, OnDestroy {

  constructor(  
    private msalService: MsalService,
  ) {
     }

  ngOnInit(): void {
      this.msalService.handleRedirectObservable().subscribe();
  }
}
Otter answered 15/3, 2023 at 16:2 Comment(3)
For me this solution helped except I didn't add the 'auth' in the provedRouter and I didn't subscribe to the handleRedirect in the app component, instead in the service. handleRedirect$: Observable<AuthenticationResult> = this.msalService.handleRedirectObservable(); And then in the ngOnInit() { this.handleRedirect$.pipe(takeUntil(this._destroying$)).subscribe(); }Bhili
I used auth because i prefered to separate the auth callback from the 'real' routes navigation. For the handleRedirect, msalService is already a service, so I didn't see the use of re-wraped it in a service for only a single observable.Otter
For me it did not work. :(Dropsy

© 2022 - 2024 — McMap. All rights reserved.