pass ui_locales to Msal Angular Guard

732 Views Asked by At

I am using the Msal Guard in my Angular application.

I also have localization in my project. I know that I can use the extraQueryParameters { ui_locales: 'de' } in my RedirectRequest object which I can then pass to the msalAuthService.loginRedirect method.

But the msalGuard automatically does the login redirect when the user tries to navigate to a protected page. I wonder is there a way to pass the ui_locales to the msalGuard somehow? Or do I need to write my own custom guard to do this.

1

There are 1 best solutions below

0
On

My solution was to write my own custom guard copying the code for the guard from github from Microsoft: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/src/msal.guard.ts

Then I adapted the class which I copied, first by injecting the language, I have language service for this:

 export class MsalLocaleGuard
    implements CanActivate, CanActivateChild, CanLoad {
    private loginFailedRoute?: UrlTree;
    protected subsink = new SubSink();
    currentLanguage: string | undefined;

    constructor(
        @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,
        private msalBroadcastService: MsalBroadcastService,
        private authService: MsalService,
        private location: Location,
        private router: Router,
        private languageService: LanguageService
    ) {
        super();
        // Subscribing so events in MsalGuard will set inProgress$ observable
        this.msalBroadcastService.inProgress$.subscribe();

        if (this.languageService.currentName) {
            this.subsink.sink = this.languageService.currentName.subscribe(
                (lang) => (this.currentLanguage = lang)
            );
        }
    }

Then I had to change the method loginInteractively to pass the current language as the ui-locales property. This is the line I added: extraQueryParameters: { ui_locales: this.currentLanguage }, And the whole method is shown below:

/**
 * Interactively prompt the user to login
 * @param url Path of the requested page
 */
private loginInteractively(state: RouterStateSnapshot): Observable<boolean> {
    // const authRequest = typeof this.msalGuardConfig.authRequest === "function"
    //     ? this.msalGuardConfig.authRequest(this.authService, state)
    //     : { ...this.msalGuardConfig.authRequest };
    if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
        this.authService.getLogger().verbose('Guard - logging in by popup');
        return this.authService
            .loginPopup(this.msalGuardConfig.authRequest as PopupRequest)
            .pipe(
                map((response: AuthenticationResult) => {
                    this.authService
                        .getLogger()
                        .verbose(
                            'Guard - login by popup successful, can activate, setting active account'
                        );
                    this.authService.instance.setActiveAccount(response.account);
                    return true;
                })
            );
    }

    this.authService.getLogger().verbose('Guard - logging in by redirect');
    const redirectStartPage = this.getDestinationUrl(state.url);
    return this.authService
        .loginRedirect({
            redirectStartPage,
            //...authRequest,
            ...this.msalGuardConfig.authRequest,
            extraQueryParameters: { ui_locales: this.currentLanguage },
        } as RedirectRequest)
        .pipe(map(() => false));
}

Then I used this new MsalLocaleGuard in the providers section of my app.module.

This is not an optimal solution, because when Microsoft update the code in their guard, then the code in my guard which copied from github becomes outdated. But it is a workaround which suffices until there is a better way.