Skip to content

Latest commit

 

History

History
433 lines (296 loc) · 20.2 KB

File metadata and controls

433 lines (296 loc) · 20.2 KB

Errors


BrowserConfigurationAuthErrors

  1. stubbed_public_client_application_called

BrowserAuthErrors

  1. interaction_in_progress
  2. block_iframe_reload
  3. monitor_window_timeout
  4. hash_empty_error
  5. hash_does_not_contain_known_properties
  6. unable_to_acquire_token_from_native_platform
  7. native_connection_not_established
  8. uninitialized_public_client_application

Other

  1. Access to fetch at [url] has been blocked by CORS policy

BrowserConfigurationAuthErrors

stubbed_public_client_application_called

Error Message: Stub instance of Public Client Application was called. If using msal-react, please ensure context is not used without a provider.

See msal-react errors

BrowserAuthErrors

Interaction_in_progress

Error Message: Interaction is currently in progress. Please ensure that this interaction has been completed before calling an interactive API.

This error is thrown when an interactive API (loginPopup, loginRedirect, acquireTokenPopup, acquireTokenRedirect) is invoked while another interactive API is still in progress. The login and acquireToken APIs are async so you will need to ensure that the resulting promises have resolved before invoking another one.

Using loginPopup or acquireTokenPopup

Ensure that the promise returned from these APIs has resolved before invoking another one.

❌ The following example will throw this error because loginPopup will still be in progress when acquireTokenPopup is called:

const request = { scopes: ["openid", "profile"] };
loginPopup();
acquireTokenPopup(request);

✔️ To resolve this you should ensure all interactive APIs have resolved before invoking another one:

const request = { scopes: ["openid", "profile"] };
await msalInstance.loginPopup();
await msalInstance.acquireTokenPopup(request);

Using loginRedirect or acquireTokenRedirect

When using redirect APIs, handleRedirectPromise must be invoked when returning from the redirect. This ensures that the token response from the server is properly handled and temporary cache entries are cleaned up. This error is thrown when handleRedirectPromise has not had a chance to complete before the application invokes loginRedirect or acquireTokenRedirect.

❌ The following example will throw this error because handleRedirectPromise will still be processing the response from a previous loginRedirect call when loginRedirect is called a 2nd time:

msalInstance.handleRedirectPromise();

const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
    // No user signed in
    msalInstance.loginRedirect();
}

✔️ To resolve, you should wait for handleRedirectPromise to resolve before calling any interactive API:

await msalInstance.handleRedirectPromise();

const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
    // No user signed in
    msalInstance.loginRedirect();
}

Or alternatively:

msalInstance
    .handleRedirectPromise()
    .then((tokenResponse) => {
        if (!tokenResponse) {
            const accounts = msalInstance.getAllAccounts();
            if (accounts.length === 0) {
                // No user signed in
                msalInstance.loginRedirect();
            }
        } else {
            // Do something with the tokenResponse
        }
    })
    .catch((err) => {
        // Handle error
        console.error(err);
    });

Note: If you are calling loginRedirect or acquireTokenRedirect from a page that is not your redirectUri you will need to ensure handleRedirectPromise is called and awaited on both the redirectUri page as well as the page that you initiated the redirect from. This is because the redirectUri page will initiate a redirect back to the page that originally invoked loginRedirect and that page will process the token response.

Wrapper Libraries

If you are using one of our wrapper libraries (React or Angular), please see the error docs in those specific libraries for additional reasons you may be receiving this error:

If you are not using any of the wrapper libraries but concerned that your application might trigger concurrent interactive requests, you should check if any other interaction is in progress prior to invoking an interaction in your token acquisition method. You can achieve this by implementing a global application state or a broadcast service etc. that emits the current MSAL interaction status via MSAL Events API.

❌ The following example will throw this error because the acquireTokenPopup in the catch block does not check if there is another interaction taking place at the moment:

async function myAcquireToken(request) {
    const msalInstance = getMsalInstance(); // get the msal application instance

    const tokenRequest = {
        account: msalInstance.getActiveAccount() || null,
        ...request
    };

    let tokenResponse;

    try {
        // attempt silent acquisition first
        tokenResponse = await msalInstance.acquireTokenSilent(tokenRequest);
    } catch (error) {
        if (error instanceof InteractionRequiredAuthError) {
            try {
                tokenResponse = await msalInstance.acquireTokenPopup(tokenRequest);
            } catch (err) {
                console.log(err);
                // handle other errors
            }
        }

        console.log(error);
        // handle other errors
    }

    return tokenResponse;
};

const request = {
    scopes: ["User.Read"]
};

myAcquireToken(request);
myAcquireToken(request);

✔️ To resolve, you should wait for the interaction status to be None before calling any other interactive API:

async function myAcquireToken(request) {
    const msalInstance = getMsalInstance(); // get the msal application instance

    const tokenRequest = {
        account: msalInstance.getActiveAccount() || null,
        ...request
    };

    let tokenResponse;

    try {
        // attempt silent acquisition first
        tokenResponse = await msalInstance.acquireTokenSilent(tokenRequest);
    } catch (error) {
        if (error instanceof InteractionRequiredAuthError) {
            // check for any interactions
            if (myGlobalState.getInteractionStatus() !== InteractionStatus.None) {
                // throw a new error to be handled in the caller below
                throw new Error("interaction_in_progress");
            } else {
                // no interaction, invoke popup flow
                tokenResponse = await msalInstance.acquireTokenPopup(tokenRequest);
            }
        }

        console.log(error);
        // handle other errors
    }

    return tokenResponse;
};

async function myInteractionInProgressHandler() {
    /**
     * "myWaitFor" method polls the interaction status via getInteractionStatus() from
     * the application state and resolves when it's equal to "None".
     */
    await myWaitFor(() => myGlobalState.getInteractionStatus() === InteractionStatus.None);

    // wait is over, call myAcquireToken again to re-try acquireTokenSilent
    return (await myAcquireToken(tokenRequest));
};

const request = {
    scopes: ["User.Read"]
};

myAcquireToken(request).catch((e) => myInteractionInProgressHandler());
myAcquireToken(request).catch((e) => myInteractionInProgressHandler());

Troubleshooting Steps

  • Enable verbose logging and trace the order of events. Verify that handleRedirectPromise is called and returns before any login or acquireToken API is called.

If you are unable to figure out why this error is being thrown please open an issue and be prepared to share the following information:

  • Verbose logs
  • A sample app and/or code snippets that we can use to reproduce the issue
  • Refresh the page. Does the error go away?
  • Open your application in a new tab. Does the error go away?

block_iframe_reload

Error Message: Request was blocked inside an iframe because MSAL detected an authentication response.

This error is thrown when calling ssoSilent or acquireTokenSilent and the page used as your redirectUri is attempting to invoke a login or acquireToken function. Our recommended mitigation for this is to set your redirectUri to a blank page that does not implement MSAL when invoking silent APIs. This will also have the added benefit of improving performance as the hidden iframe doesn't need to render your page.

✔️ You can do this on a per request basis, for example:

msalInstance.acquireTokenSilent({
    scopes: ["User.Read"],
    redirectUri: "http://localhost:3000/blank.html",
});

Remember that you will need to register this new redirectUri on your App Registration.

If you do not want to use a dedicated redirectUri for this purpose, you should instead ensure that your redirectUri is not attempting to call MSAL APIs when rendered inside the hidden iframe used by the silent APIs.

monitor_window_timeout

Error Messages:

  • Token acquisition in iframe failed due to timeout.

This error can be thrown when calling ssoSilent, acquireTokenSilent, acquireTokenPopup or loginPopup and there are several reasons this could happen. These are a few of the most common:

  1. The page you use as your redirectUri is removing or manipulating the hash
  2. The page you use as your redirectUri is automatically navigating to a different page
  3. You are being throttled by your identity provider. The identity provider may throttle clients that make too many similar requests in a short period of time. Never implement an endless retry mechanism or retry more than once. Attempts to retry non-network errors typically yield the same result. See throttling guide for more details.
  4. Your identity provider did not redirect back to your redirectUri.

Important: If your application uses a router library (e.g. React Router, Angular Router), please make sure it does not strip the hash or auto-redirect while MSAL token acquisition is in progress. If possible, it is best if your redirectUri page does not invoke the router at all.

Issues caused by the redirectUri page

When you make a silent call, in some cases, an iframe will be opened and will navigate to your identity provider's authorization page. After the identity provider has authorized the user it will redirect the iframe back to the redirectUri with the authorization code or error information in the hash fragment. The MSAL instance running in the frame or window that originally made the request will extract this response hash and process it. If your redirectUri is removing or manipulating this hash or navigating to a different page before MSAL has extracted it you will receive this timeout error.

✔️ To solve this problem you should ensure that the page you use as your redirectUri is not doing any of these things, at the very least, when loaded in a popup or iframe. We recommend using a blank page as your redirectUri for silent and popup flows to ensure none of these things can occur.

You can do this on a per request basis, for example:

msalInstance.acquireTokenSilent({
    scopes: ["User.Read"],
    redirectUri: "http://localhost:3000/blank.html",
});

Remember that you will need to register this new redirectUri on your App Registration.

Notes regarding Angular and React:

  • If you are using @azure/msal-angular your redirectUri page should not be protected by the MsalGuard.
  • If you are using @azure/msal-react your redirectUri page should not render the MsalAuthenticationComponent or use the useMsalAuthentication hook.

Issues caused by the Identity Provider

Throttling

One of the most common reasons this error can be thrown is that your application has gotten stuck in a loop or made too many token requests in a short amount of time. When this happens the identity provider may throttle subsequent requests for a short time which will result in not being redirected back to your redirectUri and ultimately this error.

✔️ To resolve throttling based issues you have 2 options:

  1. Stop making requests for a short time before trying again.
  2. Invoke an interactive API, such as acquireTokenPopup or acquireTokenRedirect.
X-Frame-Options Deny

You can also get this error if the Identity Provider fails to redirect back to your application. In silent scenarios this error is sometimes accompanied by an X-Frame-Options: Deny error indicating that your identity provider is attempting to either show you an error message or is expecting interaction.

✔️ The X-Frame-Options error will usually have a url in it and opening this url in a new tab may help you discern what is happening. If interaction is required consider using an interactive API instead. If an error is being displayed, address the error.

Some B2C flows are expected to throw this error due to their need for user interaction. These flows include:

  • Password reset
  • Profile edit
  • Sign up
  • Some custom policies depending on how they are configured
Network Latency

Another potential reason the identity provider may not redirect back to your application in time may be that there is some extra network latency.

✔️ The default timeout is about 10 seconds and should be sufficient in most cases, however, if your identity provider is taking longer than that to redirect you can increase this timeout in the MSAL config with either the iframeHashTimeout, windowHashTimeout or loadFrameTimeout configuration parameters.

const msalConfig = {
    auth: {
        clientId: "your-client-id",
    },
    system: {
        windowHashTimeout: 9000, // Applies just to popup calls - In milliseconds
        iframeHashTimeout: 9000, // Applies just to silent calls - In milliseconds
        loadFrameTimeout: 9000, // Applies to both silent and popup calls - In milliseconds
    },
};

Important

Please consult the Troubleshooting Single-Sign On section of the MSAL Browser FAQ if you are having trouble with the ssoSilent API.

hash_empty_error

Error Messages:

Hash value cannot be processed because it is empty. Please verify that your redirectUri is not clearing the hash.

This error occurs when the page you use as your redirectUri is removing the hash, or auto-redirecting to another page. This most commonly happens when the application implements a router which navigates to another route, dropping the hash.

To resolve this error we recommend using a dedicated redirectUri page which is not subject to the router. For silent and popup calls it's best to use a blank page. If this is not possible please make sure the router does not navigate while MSAL token acquisition is in progress. You can do this by detecting if your application is loaded in an iframe for silent calls, in a popup for popup calls or by awaiting handleRedirectPromise for redirect calls.

hash_does_not_contain_known_properties

Error Messages:

Hash does not contain known properites. Please verify that your redirectUri is not changing the hash.

Please see explanation for hash_empty_error above. The root cause for this error is similar, the difference being the hash has been changed, rather than dropped.

unable_to_acquire_token_from_native_platform

Error Messages:

  • Unable to acquire token from native platform.

This error is thrown when calling the acquireTokenByCode API with the nativeAccountId instead of code and the app is running in an environment which does not acquire tokens from the native broker. For a list of pre-requisites please review the doc on device bound tokens.

native_connection_not_established

Error Messages:

  • Connection to native platform has not been established. Please install a compatible browser extension and run initialize().

This error is thrown when the user signed in with the native broker but no connection to the native broker currently exists. This can happen for the following reasons:

  • The Windows Accounts extension was uninstalled or disabled
  • The initialize API has not been called or was not awaited before invoking another MSAL API

uninitialized_public_client_application

Error Messages:

  • You must call and await the initialize function before attempting to call any other MSAL API.

This error is thrown when a login, acquireToken or handleRedirectPromise API is invoked before the initialize API has been called. The initialize API must be called and awaited before attempting to acquire tokens.

❌ The following example will throw this error because handleRedirectPromise is called before initialize has completed:

const msalInstance = new PublicClientApplication({
    auth: {
        clientId: "your-client-id",
    },
    system: {
        allowNativeBroker: true,
    },
});

await msalInstance.handleRedirectPromise(); // This will throw
msalInstance.acquireTokenSilent(); // This will also throw

✔️ To resolve, you should wait for initialize to resolve before calling any other MSAL API:

const msalInstance = new PublicClientApplication({
    auth: {
        clientId: "your-client-id",
    },
    system: {
        allowNativeBroker: true,
    },
});

await msalInstance.initialize();
await msalInstance.handleRedirectPromise(); // This will no longer throw this error since initialize completed before this was invoked
msalInstance.acquireTokenSilent(); // This will also no longer throw this error

Other

Errors not thrown by MSAL, such as server or cache errors.

Access to fetch at [url] has been blocked by CORS policy

This error occurs with MSAL.js v2.x and is due to improper configuration during App Registration on Azure Portal. In particular, you should ensure your redirectUri is registered as type: Single-page application under the Authentication blade in your App Registration. If done successfully, you will see a green checkmark that says:

Your Redirect URI is eligible for the Authorization Code Flow with PKCE.

image

cache_quota_exceeded

Error messages:

  • Exceeded cache storage capacity

This error occurs when MSAL.js surpasses the allotted storage limit when attempting to save token information in the configured cache storage. See here for web storage limits.

Mitigation:

  1. Make sure the configured cache storage has enough capacity to allow MSAL.js to persist token payload. The amount of cache storage required depends on the number of cached artifacts.
  2. Disable claimsBasedCachingEnabled cache config option. When enabled, it caches access tokens under a key containing the hash of the requested claims. Depending on the MSAL.js API usage, it may result in the vast number of access tokens persisted in the cache storage.