BrowserConfigurationAuthErrors
stubbed_public_client_application_called
错误消息:调用了公共客户端应用程序的存根实例。 如果使用 msal-react,请确保不要在没有提供程序的情况下使用上下文。
请参阅 msal-react 错误
BrowserAuthErrors
交互进行中
错误消息:交互当前正在进行中。 请确保在调用交互式 API 之前已完成此交互。
如果在调用一个交互式 API(loginPopup、loginRedirect、acquireTokenPopup、acquireTokenRedirect)时另一个交互式 API 仍在运行,则会引发此错误。 登录和 acquireToken API 是异步的,因此你需要确保生成的承诺已得到解决,然后才能调用另一个承诺。
使用 loginPopup 或 acquireTokenPopup
请确保从这些 API 返回的承诺已在调用另一个 API 之前得到解决。
❌ 以下示例将引发此错误,因为 loginPopup 调用时 acquireTokenPopup 仍在进行中:
const request = { scopes: ["openid", "profile"] };
loginPopup();
acquireTokenPopup(request);
✔️ 若要解决此问题,应确保在调用另一个 API 之前已解析所有交互式 API:
const request = { scopes: ["openid", "profile"] };
await msalInstance.loginPopup();
await msalInstance.acquireTokenPopup(request);
使用 loginRedirect 或 acquireTokenRedirect
使用重定向 API 时, handleRedirectPromise 必须在从重定向返回时调用。 这可确保正确处理来自服务器的令牌响应,并清理临时缓存条目。 当应用程序调用 loginRedirect 或 acquireTokenRedirect 之前,handleRedirectPromise 尚未有机会完成时,会引发此错误。
❌以下示例会抛出此错误,因为当loginRedirect被第二次调用时,handleRedirectPromise仍在处理前一次loginRedirect调用的响应:
msalInstance.handleRedirectPromise();
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
// No user signed in
msalInstance.loginRedirect();
}
✔️ 若要解决,应在调用任何交互式 API 之前等待 handleRedirectPromise 解析:
await msalInstance.handleRedirectPromise();
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) {
// No user signed in
msalInstance.loginRedirect();
}
或者说:
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);
});
注意: 如果您是从并非您的 redirectUri 的页面调用 loginRedirect 或 acquireTokenRedirect,则需要确保在 redirectUri 页面以及发起重定向的页面上都调用并等待 handleRedirectPromise。 这是因为页面 redirectUri 将启动重定向回最初调用 loginRedirect 的页面,该页将处理令牌响应。
包装器库
如果您使用的是我们的某个封装库(React 或 Angular),请参阅这些特定库中的错误文档,以了解您可能收到此错误的其他原因:
如果您未使用任何包装器库,但担心您的应用程序可能会触发并发交互式请求,则应在令牌获取方法中发起交互之前,先检查是否已有其他交互正在进行。 可以通过实现全局应用程序状态或广播服务等来实现此目的,该服务通过 MSAL 事件 API 发出当前 MSAL 交互状态。
❌ 以下示例将引发此错误,因为 catch 块中的 acquireTokenPopup 未检查当前是否正在进行另一项交互:
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);
✔️ 若要解决此问题,应先等待交互状态变为 None,然后再调用任何其他交互式 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());
故障排除步骤
-
启用详细日志记录 并跟踪事件的顺序。 请确保在调用任何
login或acquireTokenAPI 之前,handleRedirectPromise已被调用并已返回。
如果无法确定引发此错误的原因,请 打开问题 并准备共享以下信息:
- 详细日志
- 可用于重现问题的示例应用和/或代码片段
- 刷新页面。 错误是否消失?
- 在新选项卡中打开应用程序。错误是否消失?
block_iframe_reload
错误消息:由于 MSAL 检测到身份验证响应,请求在 iframe 内被阻止。
当调用 ssoSilent 或 acquireTokenSilent 时,如果用作 redirectUri 的页面正尝试调用登录或 acquireToken 函数,则会引发此错误。
我们建议的缓解措施是:在调用无提示 API 时,将您的 redirectUri 设为空白页,且该页未实现 MSAL。 这也将具有提高性能的附加优势,因为隐藏的 iframe 不需要呈现页面。
✔️ 可以按请求执行此操作,例如:
msalInstance.acquireTokenSilent({
scopes: ["User.Read"],
redirectUri: "http://localhost:3000/blank.html",
});
请记住,需要在应用注册中注册此新 redirectUri 内容。
如果你不想为此使用专用的 redirectUri,则应确保 redirectUri 在被静默 API 使用的隐藏 iframe 中渲染时,不会尝试调用 MSAL API。
monitor_window_timeout
错误消息:
- 由于超时,iframe 中的令牌获取失败。
调用ssoSilent时可能会引发此错误,acquireTokenSilentacquireTokenPopup或者loginPopup有几种原因可能导致此错误。 以下是一些最常见的方法:
- 你用作
redirectUri的页面正在删除或篡改哈希 - 你用作
redirectUri的页面正在自动跳转到另一个页面 - 你正受到标识提供者的限制
- 你的标识提供者未将你重定向回你的
redirectUri。
重要说明:如果应用程序使用路由器库(例如 React 路由器、Angular 路由器),请确保它在 MSAL 令牌获取正在进行时不会去除哈希或自动重定向。 如果可能,最好让你的 redirectUri 页面完全不调用路由器。
由 redirectUri 页面引起的问题
当您进行静默调用时,在某些情况下,系统会打开一个 iframe,并跳转到您的身份提供商的授权页面。 身份提供方在授权用户后,会将 iframe 重定向回 redirectUri,并在哈希片段中附带授权代码或错误信息。 最初发出请求的帧或窗口中运行的 MSAL 实例将提取此响应哈希并对其进行处理。 如果您的 redirectUri 在 MSAL 提取此哈希之前将其删除、修改,或导航到其他页面,您将收到此超时错误。
✔️ 若要解决此问题,你应确保你用作 redirectUri 的页面在弹出窗口或 iframe 中加载时,至少不会执行上述任何操作。 我们建议在静默流程和弹出窗口流程中将 redirectUri 设置为空白页面,以确保不会发生上述任何情况。
可以按请求执行此操作,例如:
msalInstance.acquireTokenSilent({
scopes: ["User.Read"],
redirectUri: "http://localhost:3000/blank.html",
});
请记住,需要在应用注册中注册此新 redirectUri 内容。
有关 Angular 和 React 的说明:
- 如果您正在使用
@azure/msal-angular,则您的redirectUri页面不应受MsalGuard保护。 - 如果您正在使用
@azure/msal-react,那么您的redirectUri页面不应渲染MsalAuthenticationComponent,也不应使用useMsalAuthenticationHook。
标识提供者引起的问题
Throttling
引发此错误的最常见原因之一是应用程序在一个循环中停滞或短时间内发出了过多的令牌请求。 发生这种情况时,标识提供者可能会在短时间内对后续请求进行限流,这将导致无法重定向回你的 redirectUri,最终引发此错误。
✔️ 若要解决因流量限制导致的问题,你有两种选择:
- 请先暂停发送请求,稍后再重试。
- 调用交互式 API,例如
acquireTokenPopup或acquireTokenRedirect。
X-Frame-Options 拒绝
如果身份提供程序未能重定向回你的应用程序,你也可能会遇到此错误。 在静默场景中,此错误有时还会伴随出现 X-Frame-Options: Deny 错误,这表明身份提供程序正尝试向你显示错误消息,或者正在等待用户交互。
✔️ X-Frame-Options 错误通常会有一个 URL,并在新选项卡中打开此 URL 可能有助于识别正在发生的情况。 如果需要交互,请考虑改用交互式 API。 如果显示错误,请解决该错误。
由于需要用户交互,某些 B2C 流应引发此错误。 这些流包括:
- 密码重置
- 编辑个人资料
- 注册
- 某些自定义策略取决于它们的配置方式
网络延迟
标识提供者可能无法及时重定向回应用程序的另一个潜在原因可能是存在一些额外的网络延迟。
✔️ 默认超时时间约为 10 秒,在大多数情况下通常已足够。不过,如果身份提供程序将您重定向所花费的时间超过该时长,则可以在 MSAL 配置中通过 iframeHashTimeout、windowHashTimeout 或 loadFrameTimeout 配置参数之一来增加此超时时间。
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
},
};
hash_empty_error
错误消息:
无法处理哈希值,因为它为空。 请确认您的 redirectUri 没有清除哈希值。
当用作 redirectUri 的页面删除哈希或自动重定向到另一个页面时,会发生此错误。 当应用程序实现导航到另一个路由的路由器,删除哈希时,通常会发生这种情况。
若要解决此错误,我们建议使用不受路由器约束的专用 redirectUri 页面。 对于静默调用和弹出式调用,最好使用空白页。 如果无法做到这一点,请确保在 MSAL 令牌获取过程中,路由器不会进行导航。 你可以通过检测应用程序是否加载在 iframe 中(用于静默调用)、是否加载在弹出窗口中(用于弹出窗口调用),或者等待 handleRedirectPromise(用于重定向调用)来实现这一点。
哈希不包含已知属性
错误消息:
哈希不包含已知属性。 请验证 redirectUri 是否未更改哈希。
请参阅上述 hash_empty_error 的说明。 此错误的根本原因与前者类似,不同之处在于哈希值被更改了,而不是被删除了。
无法从原生平台获取令牌
错误消息:
- 无法从原生平台获取令牌。
当使用 nativeAccountId 而非 code 调用 acquireTokenByCode API,且应用在无法从原生代理获取令牌的环境中运行时,就会引发此错误。 有关先决条件列表,请查看 设备绑定令牌上的文档。
本机连接未建立
错误消息:
- 尚未建立与本机平台的连接。 请安装兼容的浏览器扩展并运行 initialize()。
当用户使用本机代理登录但当前不存在与本机代理的连接时,将引发此错误。 这可能是由以下原因引起的:
- Windows 帐户扩展已卸载或禁用
- 在调用另一个 MSAL API 之前,
initializeAPI 尚未被调用或尚未完成等待
未初始化的公共客户端应用程序
错误消息:
- 在尝试调用任何其他 MSAL API 之前,必须调用并等待初始化函数。
如果在调用 initialize API 之前调用了 login、acquireToken 或 handleRedirectPromise API,就会抛出此错误。 必须先调用并等待 initialize API 完成,然后才能尝试获取令牌。
❌ 以下示例将引发此错误,因为在 handleRedirectPromise 初始化完成之前调用:
const msalInstance = new PublicClientApplication({
auth: {
clientId: "your-client-id",
},
system: {
allowNativeBroker: true,
},
});
await msalInstance.handleRedirectPromise(); // This will throw
msalInstance.acquireTokenSilent(); // This will also throw
✔️ 若要解析,应在调用任何其他 MSAL API 之前等待 initialize 解析:
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
非由 msal 抛出的错误,例如服务器错误
对 [url] 的 fetch 请求已被 CORS 策略阻止
此错误发生在 v2.x MSAL.js,是由于在Azure 门户应用注册期间配置不当。 具体而言,您应确保在应用注册的 身份验证 边栏下,将您的 redirectUri 注册为 Single-page application 类型。 如果操作成功,你将看到一个绿色对勾,显示为:
重定向 URI 符合使用 PKCE 的授权代码流的条件。