microsoft-authentication-library-for-js: Angular 16: BrowserAuthError: uninitialized_public_client_application: You must call and await the initialize function before attempting to call any other MSAL API.
Core Library
MSAL.js (@azure/msal-browser)
Core Library Version
3.0.8
Wrapper Library
MSAL Angular (@azure/msal-angular)
Wrapper Library Version
None
Public or Confidential Client?
Public
Description
I am trying to authenticate user during the page load it self because, i want to authenticate user with out any button click. To achieve that i was trying to use loginRedirect in onInit
life cycle hook of app.component.ts file, When i was trying to do like that i am facing an issue
BrowserAuthError: uninitialized_public_client_application: You must call and await the initialize function before attempting to call any other MSAL API.
Is there any other way to authenticate user with out any button click
Error Message
BrowserAuthError: uninitialized_public_client_application: You must call and await the initialize function before attempting to call any other MSAL API. For more visit: aka.ms/msaljs/browser-errors BrowserAuthError: uninitialized_public_client_application: You must call and await the initialize function before attempting to call any other MSAL API. For more visit: aka.ms/msaljs/browser-errors
Msal Logs
No response
MSAL Configuration
{
auth: {
clientId: environment.msalConfig.auth.clientId,
authority: environment.msalConfig.auth.authority,
redirectUri: window.location.origin,
postLogoutRedirectUri: '/'
},
cache: {
cacheLocation: BrowserCacheLocation.LocalStorage
},
}
Relevant Code Snippets
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy{
title = 'sso-poc';
loginDisplay = false;
private readonly _destroying$ = new Subject<void>();
constructor(private msalBroadcastService: MsalBroadcastService ,private authService: MsalService) {}
ngOnDestroy(): void {
this._destroying$.next(undefined);
this._destroying$.complete();
}
ngAfterViewInit(): void {
}
//AD auth
ngOnInit(): void {
this.authService.loginRedirect();
this.msalBroadcastService.inProgress$
.pipe(
filter((status: InteractionStatus) => status === InteractionStatus.None),
takeUntil(this._destroying$)
)
.subscribe(() => {
this.setLoginDisplay();
this.checkAndSetActiveAccount();
})
}
checkAndSetActiveAccount(){
/**
* If no active account set but there are accounts signed in, sets first account to active account
* To use active account set here, subscribe to inProgress$ first in your component
* Note: Basic usage demonstrated. Your app may require more complicated account selection logic
*/
let activeAccount = this.authService.instance.getActiveAccount();
if (!activeAccount && this.authService.instance.getAllAccounts().length > 0) {
let accounts = this.authService.instance.getAllAccounts();
this.authService.instance.setActiveAccount(accounts[0]);
}
}
loginRedirect() {
this.authService.loginRedirect()
}
setLoginDisplay() {
this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
}
}
app.module.ts
export function MSALInstanceFactory(): IPublicClientApplication {
return new PublicClientApplication({
auth: {
clientId: environment.msalConfig.auth.clientId,
authority: environment.msalConfig.auth.authority,
redirectUri: window.location.origin+"/login",
postLogoutRedirectUri: window.location.origin+"/redirect-auth",
navigateToLoginRequestUrl: true
},
cache: {
cacheLocation: BrowserCacheLocation.LocalStorage,
},
system: {
allowNativeBroker: false
}
})
}
/**
* Configuring the AAD login type and api related permissions
* @returns AAD Guard configuration
*/
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
return {
interactionType: InteractionType.Redirect,
authRequest: {
scopes: [...environment.apiConfig.scopes]
},
loginFailedRoute: '/'
}
}
/**
* Interceptor configuration for the API calls
* @returns
*/
export function MSALInterceptorConfig(): MsalInterceptorConfiguration {
const protectedResourceMap = new Map<string, Array<string>>();
protectedResourceMap.set(environment.apiConfig.uri, environment.apiConfig.scopes)
return {
interactionType: InteractionType.Redirect,
protectedResourceMap
}
}
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
MsalModule,
AppRoutingModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule,
NoopAnimationsModule ,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: MsalInterceptor,
multi: true
},
{
provide: MSAL_INSTANCE,
useFactory: MSALInstanceFactory,
},
{
provide: MSAL_GUARD_CONFIG,
useFactory: MSALGuardConfigFactory
},
{
provide: MSAL_INTERCEPTOR_CONFIG,
useFactory: MSALInterceptorConfig
},
MsalService,
MsalGuard,
MsalConfigService
],
bootstrap: [AppComponent, MsalRedirectComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {
}
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SsoPoc</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<app-redirect></app-redirect>
</body>
</html>
package.json
{
"name": "sso-poc",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^16.1.0-next.0",
"@angular/common": "^16.1.0-next.0",
"@angular/compiler": "^16.1.0-next.0",
"@angular/core": "^16.1.0-next.0",
"@angular/forms": "^16.1.0-next.0",
"@angular/platform-browser": "^16.1.0-next.0",
"@angular/platform-browser-dynamic": "^16.1.0-next.0",
"@angular/router": "^16.1.0-next.0",
"@azure/msal-angular": "^3.0.8",
"@azure/msal-browser": "^3.5.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^16.1.0-next.0",
"@angular/cli": "~16.1.0-next.0",
"@angular/compiler-cli": "^16.1.0-next.0",
"@types/jasmine": "~4.3.0",
"jasmine-core": "~4.6.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.0.0",
"typescript": "~5.0.2"
}
}
Reproduction Steps
- Run
ng serve
in terminal
Expected Behavior
- User should authenticate successfully with out any button click or once web page was loaded successfully .
- User should navigate to next page once authentication was done
Identity Provider
Azure AD / MSA
Browsers Affected (Select all that apply)
Chrome, Firefox, Edge
Regression
No response
Source
Internal (Microsoft)
About this issue
- Original URL
- State: closed
- Created 8 months ago
- Reactions: 1
- Comments: 20 (4 by maintainers)
I am calling authService.initialize() (not awaited) in the constructor of the app.component.ts. It returns an Observable<void> object and I wonder if there should be a callback function in subscribe, to handle what should happen when the initialization is done.
I have the exact same problem. I have looked at the sample application code: https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-angular-v3-samples/angular16-sample-app, but I cannot find anywhere in this sample code where the public client application is initialized. If i initialize it in the app.module.ts, I get an error because the MSALInstanceFactory method is async, which it is not in your sample code.
@lalimasharda , I tried like this but i am facing the issue called
**BrowserAuthError: interaction_in_progress: Interaction is currently in progress. Please ensure that this interaction has been completed before calling an interactive API.**
Since iām using the RedirectComponent istead of
handleRedirectObservable
i made the changes like this in app.component.tsError i am getting:
Could you please let me know what am i missing here š