BrowserConfigurationAuthErrors
- interaction_in_progress
- block_iframe_reload
- monitor_window_timeout
- hash_empty_error
- hash_does_not_contain_known_properties
- unable_to_acquire_token_from_native_platform
- native_connection_not_established
- uninitialized_public_client_application
Error Message: Stub instance of Public Client Application was called. If using msal-react, please ensure context is not used without a provider.
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.
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);
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.
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());
- Enable verbose logging and trace the order of events. Verify that
handleRedirectPromise
is called and returns before anylogin
oracquireToken
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?
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.
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:
- The page you use as your
redirectUri
is removing or manipulating the hash - The page you use as your
redirectUri
is automatically navigating to a different page - 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.
- 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.
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
yourredirectUri
page should not be protected by theMsalGuard
. - If you are using
@azure/msal-react
yourredirectUri
page should not render theMsalAuthenticationComponent
or use theuseMsalAuthentication
hook.
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:
- Stop making requests for a short time before trying again.
- Invoke an interactive API, such as
acquireTokenPopup
oracquireTokenRedirect
.
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
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.
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.
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.
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.
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
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: {
allowPlatformBroker: 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: {
allowPlatformBroker: 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
Errors not thrown by MSAL, such as server or cache errors.
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.
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:
- 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.
- 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.