Errors

BrowserConfigurationAuthErrors

已呼叫模擬的公用戶端應用程式

錯誤訊息:已呼叫公用用戶端應用程式的 Stub 執行個體。 若使用 msal-react,請確保不要在沒有 Provider 的情況下使用 context。

參見 msal-react 錯誤

瀏覽器認證錯誤

互動進行中

錯誤訊息:互動正在進行中。 請確保此互動已完成,然後再呼叫互動式 API。

當呼叫互動式 API(loginPopup, loginRedirect, acquireTokenPopup, acquireTokenRedirect) 而另一個互動式 API 仍在進行中時,會跳出此錯誤。 登入與 acquireToken API 是非同步的,因此你需要確保產生的承諾已經解決,才能再呼叫下一個承諾。

使用 loginPopup 或 acquireTokenPopup

在呼叫下一個 API 之前,請確保這些 API 回傳的承諾已經解決。

❌ 以下範例會拋出這個錯誤,因為呼叫 acquireTokenPopup 時,loginPopup 仍在執行中:

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

✔️ 為了解決這個問題,你應該確保所有互動式 API 都已解決,然後再呼叫下一個:

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

使用 loginRedirect 或 acquireTokenRedirect

使用重定向 API 時, handleRedirectPromise 必須在從重定向返回時呼叫。 這可確保來自伺服器的權杖回應會被妥善處理,並移除暫時性的快取項目。 當 handleRedirectPromise 尚未有機會完成,而應用程式就在此之前呼叫 loginRedirect 或 acquireTokenRedirect 時,就會拋出此錯誤。

❌ 以下範例會拋出此錯誤,因為 handleRedirectPromise 當第二次呼叫時,仍會處理先前 loginRedirect 通話 loginRedirect 的回應:

msalInstance.handleRedirectPromise();

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

✔️ 若要解決此問題,你應該先等待 handleRedirectPromise 完成,再呼叫任何互動式 API:

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 互動狀態來達成此目標。

❌以下範例會產生此錯誤,因為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());

疑難排解步驟

  • 啟用詳細記錄,並追蹤事件發生的順序。 先確認 handleRedirectPromise 已被呼叫並已傳回,再呼叫任何 login 或 acquireToken API。

如果你無法找出這個錯誤發生的原因,請 開啟一個問題 ,並準備分享以下資訊:

  • 冗長日誌
  • 一個範例應用程式和/或程式碼片段,我們可以用來重現這個問題
  • 重新整理頁面。 錯誤會消失嗎?
  • 在新分頁開啟你的申請。錯誤會消失嗎?

block_iframe_reload

錯誤訊息:請求在 iframe 內被阻擋,因為 MSAL 偵測到驗證回應。

當呼叫 ssoSilent 或 acquireTokenSilent,且用作 redirectUri 的頁面正嘗試呼叫 login 或 acquireToken 函式時,便會擲回此錯誤。 我們建議的緩解方法是將 IP redirectUri 設定為一個空白頁面,呼叫靜默 API 時不實作 MSAL。 這還能提升效能,因為隱藏的 iframe 不需要渲染你的頁面。

✔️ 你可以針對每個請求分別這樣做,例如:

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

請記得你需要在應用程式註冊時登記這個新帳戶 redirectUri 。

如果你不想為此用途使用專用的 redirectUri,則應確保你的 redirectUri 在隱藏於供靜默 API 使用的 iframe 中進行轉譯時,不會嘗試呼叫 MSAL API。

監視視窗逾時

錯誤訊息:

  • iframe 的代幣取得因逾時而失敗。

這個錯誤可能在呼叫 ssoSilent、 或 acquireTokenSilent時 acquireTokenPopuploginPopup 出現,原因有多種。 以下是最常見的幾種:

  1. 你作為 redirectUri 使用的頁面正在移除或修改雜湊值
  2. 你使用的 redirectUri 頁面會自動導向另一個頁面
  3. 你目前正遭到身分識別提供者限流
  4. 您的身分識別提供者沒有重新導向回您的 redirectUri。

重要提示:如果您的應用程式使用路由器函式庫(例如 React Router、Angular Router),請確保在取得 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,也不應使用 useMsalAuthentication Hook。

身份提供者造成的問題

Throttling

這個錯誤最常見的原因之一是你的應用程式陷入迴圈,或在短時間內發出過多令牌請求。 當這種情況發生時,身分提供者可能會在短時間內暫時限制後續要求,導致您無法重新導向回您的 redirectUri,最終出現此錯誤。

✔️ 要解決因限速而產生的問題,有兩個選擇:

  1. 先暫停請求,再嘗試。
  2. 呼叫互動式 API,例如 acquireTokenPopup 或 acquireTokenRedirect。
X-Frame-Options 否認

如果身份提供者未能重定向回你的應用程式,你也可能遇到這個錯誤。 在靜默情況下,此錯誤有時會伴隨 X-Frame-Options: Deny 錯誤,表示您的身份提供者正試圖向您顯示錯誤訊息或期待互動。

✔️ X-Frame-Options 錯誤通常會包含一個網址,打開新分頁的網址可能有助於你判斷發生了什麼事。 如果需要互動,可以考慮使用互動式 API。 如果顯示錯誤訊息,請處理該錯誤。

部分 B2C 流程預期會因需要使用者互動而出現此錯誤。 這些流動包括:

  • 密碼重設
  • 編輯個人資料
  • 註冊
  • 某些自訂政策會視其設定方式而定
網路延遲

身份提供者無法及時重新導向你的應用程式的另一個可能原因是存在額外的網路延遲。

✔️ 預設逾時約為 10 秒,大多數情況下應該足夠,但如果你的身份提供者重定向時間超過這個時間,你可以在 MSAL 設定中透過 iframeHashTimeout或 windowHashTimeoutloadFrameTimeout 設定參數來延長這個逾時。

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 的頁面移除了 hash,或自動重新導向到另一個頁面時,就會發生此錯誤。 這種情況最常發生在應用程式實作了路由器,而該路由器在導航到另一個路由時會移除 hash。

為了解決這個錯誤,我們建議使用一個不受路由器控制的專用 redirectUri 頁面。 對於靜音和彈出式通話,最好使用空白頁。 如果無法做到,請確保路由器在 MSAL 代幣取得過程中無法導航。 你可以透過偵測應用程式是否載入於 iframe 中以進行靜默呼叫、是否載入於快顯視窗中以進行快顯視窗呼叫,或在重新導向呼叫時等待 handleRedirectPromise,來做到這一點。

雜湊不包含已知屬性

錯誤訊息:

雜湊不包含已知屬性。 請確認你的 redirectUri 沒有改變雜湊值。

請參考上述 hash_empty_error 說明。 這個錯誤的根本原因類似,不同之處在於雜湊值已被變更,而不是遭到移除。

無法從原生平台取得權杖

錯誤訊息:

  • 無法從原生平台取得代幣。

當以 nativeAccountId 而非 code 呼叫 acquireTokenByCode API,且應用程式是在不會從原生代理取得權杖的環境中執行時,就會擲回此錯誤。 關於先決條件清單,請參考關於 裝置綁定令牌的文件。

原生連線尚未建立

錯誤訊息:

  • 尚未建立與本地平台的連結。 請安裝相容的瀏覽器擴充功能並執行 initialize()。

當使用者透過原生 Broker 登入,但目前與原生 Broker 的連線不存在時,就會引發此錯誤。 發生這種情況的原因如下:

  • Windows 帳號擴充功能已被移除或停用
  • 在呼叫另一個 MSAL API 之前,initialize API 尚未被呼叫,或尚未等待其完成

未初始化的公用用戶端應用程式

錯誤訊息:

  • 你必須先呼叫並等待初始化函式,才能嘗試呼叫其他 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

✔️ 若要解決此問題,您應該先等待 initialize 完成,再呼叫任何其他 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

非由 msal 擲出的錯誤,例如伺服器錯誤

對 [url] 的 fetch 存取已遭 CORS 政策封鎖

此錯誤發生在 MSAL.js v2.x 版本,原因是 Azure 入口網站應用程式註冊時設定不當所致。 特別是,你應該確保在你的應用程式註冊中,redirectUri 已於 驗證 刀鋒視窗下註冊為類型:Single-page application。 如果成功完成,你會看到一個綠色勾勾,上面寫著:

您的重定向 URI 有資格使用 PKCE 的授權碼流程。

圖片