How to execute code before a Promise is resolved

Viewed 2256

When using the msal library one can authenticate using the redirect flow. This means the user is navigated to the Microsoft sign in page and after successful authentication he is navigated back to the SPA. The following code handles this:

auth
  .handleRedirectPromise()
  .then(() => {
    const { setAccountID } = useAccount()
    setAccountID()
  })
  .catch((error) => {
    console.log('login with redirect failed: ', error)
  })

The msal method handleRedirectPromise returns a Promise which we use to set the logged on account once it's resolved. However, it would be great if it was possible to set the state of a loading button to true before this Promise gets called.

Is there a way to "hook in" to the Promise so some code can be executed before it is called?

In pseudo terms it would be something like: If handleRedirectPromise is called set the button sate loading to true and once it's resolved set it to false.

3 Answers

The answer above from asliwinski is the right approach. Set the state of the button to loading before you instantiate PublicClientApplication, and then set the state once handleRedirectPromise has completed.

More context: MSAL.js will invoke this method in the constructor of PublicClientApplication, and it will be run on every page load, even if you are not returning from a redirect operation. This means you do not need to determine whether or not handleRedirectPromise was run, because it will run every time. You can use a combination of traditional promise semantics and the resolved value of the promise to determine what happened:

let msalLoading = true;

const msalInstance = new PublicClientApplication();

msalInstance.handleRedirectPromise()
  .then(result => {
     msalLoading = false;

     if (result) {
      // If result is truthy, your app returned from a redirect operation,
      // and it completed successfully
     } else {
       // If .then was called but result is falsey, that means your app is not returning
       // from a redirect operation (e.g. user visiting the site for the first time)
     }
  })
  .catch(error => {
     msalLoading = false;

     // If .catch is called, this means your app was returning from a redirect operation
     // and an error occurred.
   });

How about:

const temp = auth.handleRedirectPromise()

// set the button state

temp.then(() => {
    // set the button state here
    const { setAccountID } = useAccount()
    setAccountID()
  })
  .catch((error) => {
    console.log('login with redirect failed: ', error)
  })

If you use Redirect of MSAL, it will basically open new page of MS for user to be authenticated and then MSAL will redirect back to App side.

handleRedirectPromise() is initiated after MSAL gets an response. Well this is taking few seconds, so everything inside handleRedirectPromise() will took affect after that time.

So to be able to handle this time frame of few seconds After you have been redirected from MS page to App side and Before handleRedirectPromise() you can do:

  1. New black page or small amount of code to handle redirect and the promise
  2. When user clicks SignIn, I set a flag to true and then redirects to MS page. You can use localStorage or Reducer to store this flag and user it after that with getItem if you use LocalStorage or userSelector from React to get it from the store.

On return back, as we have a flag true I show loading and after handleRedirectPromise return a promise I redirect the user to Welcome page.

Related