ClientAuthError: Token renewal operation failed due to timeout MSAL Angular

Viewed 13995

I am very new MSAL. So I was only following the basic setup for implementing it from here https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/README.md.

What I did is setup configuration in app.module like this

    MsalModule.forRoot({
      auth: {
        clientId: 'myclientid', // This is your client ID
        authority: 'https://login.microsoftonline.com/mytenantid', // This is your tenant ID
        redirectUri: 'http://localhost:4200'// This is your redirect URI
       
      },
      cache: {
        cacheLocation: 'sessionStorage',
        storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
      },
    }, {
      popUp: !isIE,
      consentScopes: [
                  'user.read',
                  'openid',
                  'apiappid/user_impersonation',
                ], 
      unprotectedResources: [],
      protectedResourceMap: [
                  [
                    'https://localhost:44331/',
                    ['apiappid/user_impersonation'],
                  ]
                  
                ], 
      extraQueryParameters: {}
    })

and in routing file this was added

 {path : 'das',canActivate: [MsalGuard], component:CrMainComponent},

Here is my app.component.ts

import {
  Component,
  Injectable
} from '@angular/core';
import {
  Observable,
  Subscription
} from 'rxjs';

import {
  BroadcastService,
  MsalService
} from '@azure/msal-angular';
import {
  CryptoUtils,
  Logger,
  AuthError,
  AuthResponse
} from 'msal';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'angular-client';
  loggedIn: boolean;

  public userInfo: any = null;
  private subscription: Subscription;
  public isIframe: boolean;

  constructor(private broadcastService: BroadcastService, private authService: MsalService) {

    this.isIframe = window !== window.parent && !window.opener;

    if (this.authService.getAccount())

    {
      //console.info(JSON.stringify(this.authService.getAccount()));
      this.loggedIn = true;

    } else {

      this.loggedIn = false;
      //this.login();

    }
  }
  login()

  {

    const isIE = window.navigator.userAgent.indexOf("MSIE ") > -1 || window.navigator.userAgent.indexOf("Trident/") > -1;

    if (isIE) {
      this.authService.loginRedirect();

    } else {

      this.authService.loginPopup();

    }
  }

  logout()
  {
    this.authService.logout();

  }
  ngOnInit() {

    this.broadcastService.subscribe("msal:loginFailure", (payload) => {

      console.log("login failure " + JSON.stringify(payload));

      this.loggedIn = false;

    });

    this.broadcastService.subscribe("msal:loginSuccess", (payload) => {
      console.log("login success " + JSON.stringify(payload));
      this.loggedIn = true;
      //alert("Login Success");

    });
    this.authService.handleRedirectCallback((redirectError: AuthError, redirectResponse: AuthResponse) => {
      if (redirectError) {
        console.error("Redirect error: ", redirectError);
        return;
      }

      console.log("Redirect success: ", redirectResponse);
    });
  }

  ngOnDestroy() {

    this.broadcastService.getMSALSubject().next(1);
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }
}

So I guess since I specified Msalguard to my routing configuration Its redirecting to microsoft of Azure AD authentication and on successful auth, it redirect me back to my page. Thats all working fine.

But sometimes I am getting an error

Uncaught (in promise): ClientAuthError: Token renewal operation failed due to timeout.

Honestly I have no idea what I am missing or what I did wrong. In any of my code I am not doing any operations for the login procedure. Its all happening automatically when I have these code in place. So do we really do something to fix this token renewal issue? I mean do we need to renew the token manually?? If so how??

3 Answers

The other answers don't directly answer the question. Having read through the answers and having gone and researched the issue, I have found a solution that works for me in the issue tracking link found here (as provided in other answers). The issue still happens, but after a moment it seems to fix itself up and gets me to reauthenticate. Telling people to go look at the angular example is useless, because that doesn't include code that fixes this problem.

@NgModule({
  imports: [RouterModule.forRoot(routes,
    {
      enableTracing: false,
      useHash: true,
      initialNavigation: isInIframe() ? 'disabled' : undefined // <-THIS
    })],
  exports: [RouterModule]
})
export class AppRoutingModule {
}

export function isInIframe() {
  return window !== window.parent && !window.opener;
}

I also had to wrap my login Redirect method in a try catch block:

login(loginName: string, password: string) {
      try {
        this.authService.loginRedirect();
      }
      catch(error) {
        console.log("oh no, there's an error", error);
      }
}

Use the below code to avoid token renewal operation.

this.authService.acquireTokenPopup(requestObj).then(function (tokenResponse) {
  // Callback code here
  console.log(tokenResponse.accessToken);
}).catch(function (error) {
  console.log(error);
});

Don't use => this.authService.acquireTokenSilent

this is a workaround, actual issue track here https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/1592

For timeout error, invoke acquireTokenPopup with the same set of scopes, and then make the request again. You can refer to this

It is a known issue with the renewal problem. You can track the issue here.

If you want to use MSAL for Angular please refer to this sample

Related