Federated Credential Management API 開發人員指南

瞭解如何使用 FedCM 進行隱私權保護身分聯盟。

FedCM (Federated Credential Management) 是聯合身分識別服務 (例如「使用...登入」) 的隱私權保護做法,可讓使用者登入網站而不將個人資訊提供給身分識別服務或網站。

如要進一步瞭解 FedCM 用途、使用者流程和 API 發展藍圖,請參閱 FedCM API 簡介

FedCM 開發環境

您必須在 Chrome 的 IdP 和 RP 上設定安全背景資訊 (HTTPS 或 localhost),才能使用 FedCM。

在 Android 裝置上對 Chrome 的程式碼進行偵錯

在本機設定並執行伺服器,對 FedCM 程式碼進行偵錯。您可以在使用具備通訊埠轉送功能的 USB 傳輸線連線的 Android 裝置上,在 Chrome 中存取這個伺服器

您可以按照遠端對 Android 裝置進行偵錯的操作說明,在電腦上使用開發人員工具為 Android 上的 Chrome 偵錯。

在 Chrome 中封鎖第三方 Cookie

將 Chrome 設為封鎖,模擬逐步淘汰第三方 Cookie
設定 Chrome 封鎖第三方 Cookie,模擬逐步淘汰第三方 Cookie

您可以在 Chrome 實際強制執行 FedCM 之前,先測試 FedCM 的運作方式。

如要封鎖第三方 Cookie,請使用無痕模式,或是在電腦版設定中前往 chrome://settings/cookies 選擇「封鎖第三方 Cookie」,或是在行動裝置上依序前往「設定」>「網站設定」>「Cookie」,選擇「封鎖第三方 Cookie」。

使用 FedCM API

如要與 FedCM 整合,請建立已知檔案設定檔和端點:用於帳戶清單宣告核發和選擇用戶端中繼資料

接著,FedCM 會公開 JavaScript API,讓 RP 能夠使用 IdP 登入

建立知名檔案

為避免追蹤程式濫用 API,必須透過 IdP 的 eTLD+1/.well-known/web-identity 提供已知檔案。

舉例來說,如果 IdP 端點是在 https://accounts.idp.example/ 底下提供,就必須在 https://idp.example/.well-known/web-identityIdP 設定檔中提供已知檔案。以下是知名的檔案內容範例:

{
  "provider_urls": ["https://accounts.idp.example/config.json"]
}

JSON 檔案必須包含 provider_urls 屬性,以及包含 IdP 設定檔網址的陣列,才能依 RP 將 navigator.credentials.get 指定為 configURL 的路徑部分。陣列中的網址字串數量限制為一個,但日後可能會改變您的意見回饋。

建立 IdP 設定檔和端點

IdP 設定檔提供瀏覽器的必要端點清單。IdP 會代管這個設定檔以及必要的端點和網址。所有 JSON 回應都必須以 application/json 內容類型提供。

設定檔的網址取決於提供給 RP 所執行的 navigator.credentials.get 呼叫的值。

const credential = await navigator.credentials.get({
  identity: {
    context: 'signup',
    providers: [{
      configURL: 'https://accounts.idp.example/config.json',
      clientId: '********',
      nonce: '******'
    }]
  }
});
const { token } = credential;

將 IdP 設定檔位置的完整網址指定為 configURL。在 RP 上呼叫 navigator.credentials.get() 時,瀏覽器會使用 GET 要求擷取設定檔,但不含 Origin 標頭或 Referer 標頭。這項要求未採用 Cookie,且未追蹤重新導向。 這樣會有效防止 IdP 學習提出要求的使用者,以及嘗試連線的 RP。例如:

GET /config.json HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Sec-Fetch-Dest: webidentity

瀏覽器會預期來自 IdP 的 JSON 回應,其中包含下列屬性:

屬性 說明
accounts_endpoint (必填) 帳戶端點的網址。
client_metadata_endpoint (非必要) 用戶端中繼資料端點的網址。
id_assertion_endpoint (必填) ID 斷言端點的網址。
disconnect (非必要) 中斷連線端點的網址。
login_url (必填) 可讓使用者登入 IdP 的登入頁面網址
branding (非必要) 包含各種品牌選項的物件。
branding.background_color (非必要) 品牌宣傳選項,用來設定「以身分繼續...」按鈕的背景顏色。請使用相關的 CSS 語法,也就是 hex-colorhsl()rgb()named-color
branding.color (非必要) 品牌宣傳選項,可設定「以身分繼續...」按鈕的文字顏色。請使用相關的 CSS 語法,也就是 hex-colorhsl()rgb()named-color
branding.icons (非必要) 設定圖示物件的品牌宣傳選項,顯示在登入對話方塊中。圖示物件是包含兩個參數的陣列:
  • url (必要):圖示圖片的網址。但不支援 SVG 圖片。
  • size (選用):圖示尺寸,應用程式假設為正方形和單一解析度。這個數字必須大於或等於 25。

RP 可以透過 navigator.credentials.get()identity.context 值,修改 FedCM 對話方塊 UI 中的字串,以配合預先定義的驗證情境。選用屬性可以是 "signin" (預設)、"signup""use""continue" 其中之一。

如何將品牌宣傳元素套用至 FedCM 對話方塊
FedCM 對話方塊如何套用品牌宣傳元素

以下是 IdP 的回應主體範例:

{
  "accounts_endpoint": "/accounts.php",
  "client_metadata_endpoint": "/client_metadata.php",
  "id_assertion_endpoint": "/assertion.php",
  "disconnect_endpoint": "/disconnect.php",
  "login_url": "/login",
  "branding": {
    "background_color": "green",
    "color": "#FFEEAA",
    "icons": [{
      "url": "https://idp.example/icon.ico",
      "size": 25
    }]
  }
}

瀏覽器擷取設定檔後,會將後續要求傳送至 IdP 端點:

IdP 端點
IdP 端點

帳戶端點

IdP 的帳戶端點會傳回使用者目前在 IdP 上登入的帳戶清單。如果 IdP 支援多個帳戶,這個端點就會傳回所有已登入的帳戶。

瀏覽器傳送帶有 SameSite=NoneGET 要求,但不含 client_id 參數、Origin 標頭或 Referer 標頭。這樣可以有效防止 IdP 得知使用者嘗試登入的 RP。例如:

GET /accounts.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

收到要求後,伺服器應會進行以下操作:

  1. 確認要求包含 Sec-Fetch-Dest: webidentity HTTP 標頭。
  2. 比對工作階段 Cookie 與已登入帳戶的 ID。
  3. 回覆帳戶清單。

瀏覽器預期 JSON 回應中包含的 accounts 屬性,且該陣列的帳戶資訊陣列包含下列屬性:

屬性 說明
id (必填) 使用者的專屬 ID。
name (必填) 使用者的姓氏和名字。
email (必填) 使用者的電子郵件地址。
given_name (非必要) 使用者的名字。
picture (非必要) 使用者顯示圖片的網址。
approved_clients (非必要) 使用者註冊的 RP 用戶端 ID 陣列。
login_hints (非必要) IdP 支援指定帳戶的所有可能篩選器類型陣列。RP 可以使用 loginHint 屬性叫用 navigator.credentials.get(),選擇性地顯示指定帳戶。
domain_hints (非必要) 與該帳戶相關聯的所有網域陣列。RP 可以使用 domainHint 屬性呼叫 navigator.credentials.get() 以篩選帳戶。

回應主體範例:

{
  "accounts": [{
    "id": "1234",
    "given_name": "John",
    "name": "John Doe",
    "email": "john_doe@idp.example",
    "picture": "https://idp.example/profile/123",
    "approved_clients": ["123", "456", "789"],
    "login_hints": ["demo1", "demo1@idp.example"]
  }, {
    "id": "5678",
    "given_name": "Johnny",
    "name": "Johnny",
    "email": "johnny@idp.example",
    "picture": "https://idp.example/profile/456",
    "approved_clients": ["abc", "def", "ghi"],
    "login_hints": ["demo2", "demo2@idp.example"],
    "domain_hints": ["corp.example"]
  }]
}

如果使用者未登入,會傳回 HTTP 401 (未授權)。

傳回的帳戶清單會由瀏覽器取用,而不會提供給 RP。

用戶端中繼資料端點

IdP 的用戶端中繼資料端點會傳回依賴方的中繼資料,例如 RP 的隱私權政策和服務條款。RP 應事先提供 IdP 的隱私權政策和服務條款連結。如果使用者尚未透過 IdP 註冊 RP,就會在登入對話方塊中顯示這些連結。

瀏覽器會使用 client_id navigator.credentials.get 在沒有 Cookie 的情況下傳送 GET 要求。例如:

GET /client_metadata.php?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity

收到要求後,伺服器應會進行以下操作:

  1. 確定 client_id 的 RP。
  2. 透過用戶端中繼資料回應。

用戶端中繼資料端點的屬性包括:

屬性 說明
privacy_policy_url (非必要) 受限方隱私權政策網址。
terms_of_service_url (非必要) RP 服務條款網址。

瀏覽器預期端點應傳回 JSON 回應:

{
  "privacy_policy_url": "https://rp.example/privacy_policy.html",
  "terms_of_service_url": "https://rp.example/terms_of_service.html",
}

傳回的用戶端中繼資料會由瀏覽器使用,而不會提供給 RP。

ID 斷言端點

IdP 的 ID 斷言端點會傳回已登入使用者的宣告。 當使用者使用 navigator.credentials.get() 呼叫登入 RP 網站時,瀏覽器會向這個端點傳送含有 SameSite=NonePOST 要求,以及 POST 內容類型至 application/x-www-form-urlencoded,並提供以下資訊:

屬性 說明
client_id (必填) RP 的用戶端 ID。
account_id (必填) 登入使用者的專屬 ID。
nonce (非必要) 要求 Nonce,由 RP 提供。
disclosure_text_shown 結果會是 "true""false" 字串,而非布林值。如果未顯示揭露文字,則結果為 "false"。如果帳戶端點回應的 approved_clients 屬性清單包含 RP 的用戶端 ID,或者瀏覽器過去在沒有 approved_clients 的情況下觀察到註冊時刻,就會發生這種情況。
is_auto_selected 如果對 RP 執行自動重新驗證is_auto_selected 表示 "true"。否則為 "false"。有助於支援更多安全性相關功能。舉例來說,部分使用者可能偏好較高的安全層級,必須在驗證時明確提供使用者中介服務。如果 IdP 收到沒有這類中介服務的權杖要求,處理要求的方式可能不同。舉例來說,您可以傳回錯誤代碼,讓 RP 可以使用 mediation: required 再次呼叫 FedCM API。

HTTP 標頭示例:

POST /assertion.php HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

account_id=123&client_id=client1234&nonce=Ct60bD&disclosure_text_shown=true&is_auto_selected=true

收到要求後,伺服器應會進行以下操作:

  1. 使用 CORS (跨源資源共享) 回應要求。
  2. 確認要求包含 Sec-Fetch-Dest: webidentity HTTP 標頭。
  3. 比對 Origin 標頭與 RP 來源,由 client_id 決定。 如果不相符,則拒絕。
  4. account_id 與已登入帳戶的 ID 進行比對。如果兩者不相符,請拒絕。
  5. 以權杖回應。如果要求遭拒,請以錯誤回應回應。

符記是由 IdP 核發,但通常都會使用帳戶 ID、用戶端 ID、核發者來源 nonce 等資訊簽署,以便 RP 驗證權杖的真實性。

瀏覽器預期 JSON 回應應包含下列屬性:

屬性 說明
token (必填) 權杖是包含驗證聲明的字串。
{
  "token": "***********"
}

傳回的權杖會由瀏覽器傳遞至 RP,以便 RP 能驗證驗證。

傳回錯誤回應

id_assertion_endpoint 也可以傳回「錯誤」回應,其中包含兩個選用欄位:

  • code:IdP 可從 OAuth 2.0 指定的錯誤清單 (invalid_requestunauthorized_clientaccess_deniedserver_errortemporarily_unavailable) 中選擇一個已知的錯誤,也可以使用任何字串。如果是後者,Chrome 會顯示錯誤 UI 並顯示一般錯誤訊息,並將程式碼傳遞至 RP。
  • url:識別人類可讀的網頁,其中包含錯誤相關資訊,向使用者提供錯誤相關的其他資訊。瀏覽器無法在原生 UI 中提供豐富的錯誤訊息,因此這個欄位對使用者來說非常實用。例如後續步驟的連結、客戶服務聯絡資訊等。如果使用者想進一步瞭解錯誤詳細資料和修正方式,可以透過瀏覽器 UI 造訪提供的網頁瞭解詳情。網址必須與 IdP configURL 相同。
// id_assertion_endpoint response
{
  "error" : {
     "code": "access_denied",
     "url" : "https://idp.example/error?type=access_denied"
  }
}

取消連結端點

叫用 IdentityCredential.disconnect() 後,瀏覽器會向這個中斷連線的端點傳送含有 SameSite=None 的 Cookie 和內容類型為 application/x-www-form-urlencoded 的跨來源 POST 要求,並提供以下資訊:

屬性 說明
account_hint IdP 帳戶的提示。
client_id RP 的用戶端 ID。
POST /disconnect.php HTTP/1.1
Host: idp.example
Origin: rp.example
Content-Type: application/x-www-form-urlencoded
Cookie: 0x123
Sec-Fetch-Dest: webidentity

account_hint=account456&client_id=rp123

收到要求後,伺服器應會進行以下操作:

  1. 使用 CORS (跨源資源共享) 回應要求。
  2. 確認要求包含 Sec-Fetch-Dest: webidentity HTTP 標頭。
  3. 比對 Origin 標頭與 RP 來源,由 client_id 決定。 如果不相符,則拒絕。
  4. account_hint 與已登入帳戶的 ID 進行比對。
  5. 中斷使用者帳戶與 RP 的連線。
  6. 以 JSON 格式回應瀏覽器,指出已識別的使用者帳戶資訊。

回應 JSON 酬載的範例如下所示:

{
  "account_id": "account456"
}

如果 IdP 希望瀏覽器取消連結所有與 RP 相關聯的帳戶,請傳送不符合任何帳戶 ID 的字串,例如 "*"

登入網址

透過 Login Status API,IdP 必須通知使用者瀏覽器的登入狀態。不過,狀態可能不同步,例如工作階段到期時。在此情況下,瀏覽器可以動態讓使用者透過在 idp 設定檔login_url 中指定的登入網頁網址登入 IdP。

FedCM 對話方塊會顯示訊息建議登入,如下圖所示。

A
畫面上顯示 FedCM 對話方塊,建議登入 IdP。

使用者按一下「Continue」按鈕後,瀏覽器會開啟 IdP 登入頁面的彈出式視窗。

自有自營頻道
點選「登入 IdP」按鈕後顯示的對話方塊範例。

對話方塊是包含第一方 Cookie 的一般瀏覽器視窗。無論對話方塊的內容為何,只要是由 IdP 進行,且沒有任何視窗控點都無法對 RP 頁面發出跨源通訊要求。使用者登入後,IdP 應:

  • 傳送 Set-Login: logged-in 標頭或呼叫 navigator.login.setStatus("logged-in") API,通知瀏覽器使用者已登入。
  • 呼叫 IdentityProvider.close() 即可關閉對話方塊。
A
使用者使用 FedCM 登入 IdP 後,登入 RP。

通知瀏覽器使用者在識別資訊提供者的登入狀態

Login Status API 是一種網站,可將網站 (特別是 IdP) 告知瀏覽器使用者在 IdP 上的登入狀態。透過這個 API,瀏覽器可減少對 IdP 不必要的要求,並降低潛在的時間攻擊。

IdP 可以傳送 HTTP 標頭,或是在使用者登入 IdP 或從其所有 IdP 帳戶中登出時呼叫 JavaScript API,藉此向瀏覽器告知使用者的登入狀態。瀏覽器會為每個 IdP (透過設定網址識別) 保留一個三狀態變數,代表登入狀態,以及可能的值:logged-inlogged-outunknown。預設狀態為 unknown

如要指出使用者已登入,請在頂層導覽傳送 Set-Login: logged-in HTTP 標頭,或是在 IdP 來源傳送相同網站子資源要求:

Set-Login: logged-in

或者,您也可以在頂層導覽中從 IdP 來源呼叫 JavaScript API navigator.login.setStatus("logged-in")

navigator.login.setStatus("logged-in")

這些呼叫會將使用者的登入狀態記錄為 logged-in。當使用者的登入狀態設為 logged-in 時,呼叫 FedCM 的 RP 會向 IdP 的帳戶端點發出要求,並在 FedCM 對話方塊中向使用者顯示可用的帳戶。

如要告知使用者已登出所有帳戶,請在頂層導覽傳送 Set-Login: logged-out HTTP 標頭,或是在 IdP 來源傳送相同網站子資源要求:

Set-Login: logged-out

或者,您也可以在頂層導覽中從 IdP 來源呼叫 JavaScript API navigator.login.setStatus("logged-out")

navigator.login.setStatus("logged-out")

這些呼叫會將使用者的登入狀態記錄為 logged-out。使用者的登入狀態為 logged-out 時,如果未向 IdP 的帳戶端點發出要求,呼叫 FedCM 時就會失敗,而且不會顯示相關通知。

已設定 unknown 狀態,之後 IdP 才會使用登入狀態 API 傳送信號。導入 Unknown 是為了獲得更理想的轉換效果,因為這個 API 出貨時,使用者可能已登入 IdP。在首次叫用 FedCM 時,IdP 可能沒有機會向瀏覽器發送信號。在這種情況下,Chrome 會向 IdP 的帳戶端點發出要求,並根據帳戶端點的回應更新狀態:

  • 如果端點傳回有效帳戶的清單,請將狀態更新為 logged-in 並開啟 FedCM 對話方塊,以便顯示這些帳戶。
  • 如果端點未傳回任何帳戶,請將狀態更新為 logged-out,並失敗 FedCM 呼叫。

讓使用者透過動態登入流程登入

雖然 IdP 會持續通知使用者的登入狀態,但有時 (例如工作階段到期) 可能會不一致。登入狀態為 logged-in 時,瀏覽器會嘗試傳送憑證要求至帳戶端點,但因為工作階段已無法使用,因此伺服器不會傳回任何帳戶。在此情況下,瀏覽器可以動態讓使用者透過彈出式視窗登入 IdP

透過識別資訊提供者登入依賴方

IdP 的設定和端點可供使用時,RP 可以呼叫 navigator.credentials.get() 來要求允許使用者使用 IdP 登入 RP。

呼叫 API 之前,您需要確認 [使用者的瀏覽器可用 FedCM]。如要檢查 FedCM 是否可用,請在 FedCM 實作項目周圍包裝這段程式碼:

if ('IdentityCredential' in window) {
  // If the feature is available, take action
}

如要要求使用者從 RP 登入 IdP,請執行下列操作:

const credential = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://accounts.idp.example/config.json',
      clientId: '********',
      nonce: '******'
    }]
  }
});
const { token } = credential;

providers 屬性會採用 IdentityProvider 物件的陣列,當中包含下列屬性:

屬性 說明
configURL (必填) IdP 設定檔的完整路徑。
clientId (必填) IdP 核發的 RP 用戶端 ID。
nonce (非必要) 隨機字串,用來確保系統會針對特定要求核發回應。可避免重送攻擊。
loginHint (非必要) 只要指定帳戶端點提供的其中一個 login_hints 值,FedCM 對話方塊就會選擇性顯示指定帳戶。
domainHint (非必要) 只要指定帳戶端點提供的其中一個 domain_hints 值,FedCM 對話方塊就會選擇性顯示指定帳戶。

瀏覽器處理註冊和登入用途的方式,會因帳戶清單端點的回應中存在 approved_clients 而有所不同。如果使用者已註冊 RP,瀏覽器就不會顯示揭露文字「For continue with ...."」。

註冊狀態取決於是否已滿足下列條件:

  • 如果 approved_clients 包含 RP 的 clientId
  • 如果瀏覽器記住使用者已註冊 RP。
使用者使用 FedCM 登入 RP

當 RP 呼叫 navigator.credentials.get() 時,下列活動會發生:

  1. 瀏覽器傳送要求並擷取數個文件:
    1. 已知檔案和宣告端點的IdP 設定檔
    2. 帳戶清單
    3. 選用:從用戶端中繼資料端點擷取 RP 的隱私權政策和服務條款的網址。
  2. 瀏覽器會顯示使用者可用來登入的帳戶清單,以及服務條款和隱私權政策 (如有)。
  3. 使用者選擇要登入的帳戶後,系統會將對 ID 斷言端點的要求傳送至 IdP,以擷取憑證。
  4. RP 可以驗證符記來驗證使用者。
登入 API 呼叫
login API 呼叫

RP 應支援不支援 FedCM 的瀏覽器,因此使用者應可使用現有的非 FedCM 登入程序。在第三方 Cookie 完全淘汰前,應該不會出現問題。

RP 伺服器驗證權杖後,RP 即可註冊使用者,或讓他們登入並啟動新的工作階段。

登入提示 API

使用者登入後,依賴方 (RP) 有時會要求使用者重新驗證。但使用者可能不知道自己登入的是哪一個帳戶。如果 RP 能夠指定登入的帳戶,使用者會比較容易挑選帳戶。

RP 可藉由叫用 loginHint 屬性搭配從帳戶清單端點擷取的其中一個 login_hints 值,選擇性顯示特定帳戶,如以下程式碼範例所示:navigator.credentials.get()

return await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: "https://idp.example/manifest.json",
      clientId: "123",
      nonce: nonce,
      loginHint : "demo1@example.com"
    }]
  }
});

如果沒有帳戶與 loginHint 相符,FedCM 對話方塊會顯示登入提示,讓使用者能登入與 RP 要求提示相符的 IdP 帳戶。使用者輕觸提示時,系統會開啟彈出式視窗,其中包含設定檔中指定的登入網址。隨後連結會附上登入提示和網域提示查詢參數。

網域提示 API

在某些情況下,RP 已經知道只有與特定網域相關聯的帳戶才能登入網站。這在企業情境中尤其常見,而存取的網站僅限公司網域使用。為了提供更優質的使用者體驗,FedCM API 允許 RP 只顯示可用於登入 RP 的帳戶。這可避免使用者嘗試透過公司網域外的帳戶登入 RP 時,因為未使用正確的帳戶類型,而稍後才會顯示錯誤訊息 (或關閉登入失敗的錯誤畫面)。

RP 可藉由叫用 domainHint 屬性搭配從帳戶清單端點擷取的其中一個 domain_hints 值,選擇性顯示相符的帳戶,如以下程式碼範例所示:navigator.credentials.get()

return await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: "https://idp.example/manifest.json",
      clientId: "abc",
      nonce: nonce,
      domainHint : "corp.example"
    }]
  }
});

如果沒有帳戶與 domainHint 相符,FedCM 對話方塊會顯示登入提示,讓使用者能登入與 RP 要求提示相符的 IdP 帳戶。使用者輕觸提示時,系統會開啟彈出式視窗,其中包含設定檔中指定的登入網址。隨後連結會附上登入提示和網域提示查詢參數。

如果沒有任何帳戶與 domainHint 相符,便會顯示登入提示範例。
沒有帳戶符合 domainHint 時的登入提示範例。

顯示錯誤訊息

有時候,IdP 可能會基於正當理由 (例如用戶端未經授權,) 無法核發權杖。如果 IdP 傳回「error」回應,RP 就可以擷取該回應,Chrome 還會透過顯示 IdP 提供錯誤資訊的瀏覽器 UI 來通知使用者。

A
FedCM 對話方塊,在使用者嘗試登入失敗時顯示錯誤訊息。字串與錯誤類型相關聯。
try {
  const cred = await navigator.credentials.get({
    identity: {
      providers: [
        {
          configURL: "https://idp.example/manifest.json",
          clientId: "1234",
        },
      ],
    }
  });
} catch (e) {
  const code = e.code;
  const url = e.url;
}

取得初次同意後自動重新驗證使用者

FedCM 自動重新驗證 (簡稱「auto-reauthn」) 可讓使用者在使用 FedCM 完成初始驗證後自動重新驗證。此處的「初始驗證」是指使用者在同一個瀏覽器執行個體上首次輕觸 FedCM 登入對話方塊中的「Continue as...」按鈕,藉此建立帳戶或登入 RP 網站。

雖然在使用者建立聯合帳戶防止追蹤 (FedCM 的主要目標之一) 之前,明確的使用者體驗才顯得合理,但使用者一旦授予權限,允許 RP 與 IdP 之間進行通訊,就顯得較為麻煩:使用者授予 RP 和 IdP 之間的通訊權限後,對之前強制實行的同意聲明,使用者對隱私權或安全性也毫無助益。

使用自動重新驗證時,瀏覽器會根據您在呼叫 navigator.credentials.get() 時為 mediation 指定的選項變更行為。

const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: "https://idp.example/fedcm.json",
      clientId: "1234",
    }],
  },
  mediation: 'optional', // this is the default
});

// `isAutoSelected` is `true` if auto-reauthn was performed.
const isAutoSelected = cred.isAutoSelected;

mediationCredential Management API 中的屬性,其行為相同PasswordCredentialFederatedCredential 都相同,而且PublicKeyCredential 還獲得部分支援。此屬性接受下列四個值:

  • 'optional'(預設):盡可能自動重新驗證;如果不是,則必須提供中介服務。建議您在登入頁面上選擇這個選項。
  • 'required':一律要求中介服務才可繼續操作,例如按一下使用者介面上的「繼續」按鈕。如果使用者每次需要進行驗證時,都會明確授予權限,請選擇這個選項。
  • 'silent':如果可能,自動重新驗證;如果沒有,則在不要求中介服務的情況下失敗。建議您在專屬登入頁面以外的其他頁面中選擇此選項,例如運送網站上的商品頁面或新聞網站的文章頁面。
  • 'conditional':用於 WebAuthn,且目前不適用於 FedCM。

在此呼叫中,系統會在下列情況下自動重新驗證:

  • 可以使用 FedCM。例如,使用者尚未全域停用 FedCM,或設定中未針對 RP 停用 FedCM。
  • 使用者只使用一個具備 FedCM API 的帳戶,在這個瀏覽器中登入網站。
  • 使用者已使用該帳戶登入 IdP。
  • 過去 10 分鐘內未執行自動重新驗證。
  • 上次登入後,RP 未呼叫 navigator.credentials.preventSilentAccess()

當符合這些條件時,會嘗試在叫用 FedCM navigator.credentials.get() 後立即自動重新驗證使用者。

mediation: optional 時,可能因為只有瀏覽器知道而無法使用自動重新驗證。RP 可以透過檢查 isAutoSelected 屬性,檢查是否執行自動重新驗證。

這有助於評估 API 效能,並據此改善使用者體驗。 此外,如果無法使用,系統可能會提示使用者,透過明確的使用者中介服務登入,該中介服務流程為 mediation: required

透過 FedCM 自動重新驗證的使用者。

使用 preventSilentAccess() 強制執行中介服務

當使用者登出後立即進行自動重新驗證,並不會帶來良好的使用者體驗。這也是為什麼 FedCM 在自動重新驗證後會有一個 10 分鐘的靜止期,以防止這種行為發生。這表示自動重新驗證最多每 10 分鐘最多只會執行一次,除非使用者在 10 分鐘內重新登入。RP 應呼叫 navigator.credentials.preventSilentAccess(),明確要求瀏覽器在使用者明確登出 RP 時 (例如點選登出按鈕) 停用自動重新驗證。

function signout() {
  navigator.credentials.preventSilentAccess();
  location.href = '/signout';
}

使用者可以在「設定」中停用自動重新驗證

使用者可以透過設定選單選擇不採用自動重新驗證功能:

  • 在電腦版 Chrome 中,依序前往 chrome://password-manager/settings > 自動登入。
  • 在 Android Chrome 中,依序開啟「設定」 >「密碼管理工具」 > 依序輕觸右上角的齒輪 >「自動登入」。

停用切換按鈕之後,使用者就能完全停用自動重新驗證行為。如果使用者已在 Chrome 執行個體上登入 Google 帳戶,且已啟用同步功能,這項設定就會儲存並同步到所有裝置。

中斷 IdP 與 RP 的連線

如果使用者先前已透過 FedCM 使用 IdP 登入 RP,則瀏覽器會在本機將關係記憶為已連結的帳戶清單。RP 可能會叫用 IdentityCredential.disconnect() 函式來啟動中斷連線。這個函式可從頂層 RP 框架呼叫。RP 必須傳遞 configURL、在 IdP 下使用的 clientId,以及 accountHint 才能中斷連線 IdP。帳戶提示可以是任意字串,只要中斷連線的端點能識別帳戶 (例如電子郵件地址或使用者 ID),該 ID 不一定與帳戶清單端點所提供的帳戶 ID 相符:

// Disconnect an IdP account "account456" from the RP "https://idp.com/". This is invoked on the RP domain.
IdentityCredential.disconnect({
  configURL: "https://idp.com/config.json",
  clientId: "rp123",
  accountHint: "account456"
});

IdentityCredential.disconnect() 會傳回 Promise。這項承諾可能會擲回例外狀況,原因如下:

  • 使用者尚未透過 FedCM 使用 IdP 登入 RP。
  • 系統在沒有 FedCM 權限政策的 iframe 中叫用 API。
  • configURL 無效或缺少中斷連線端點。
  • 內容安全政策 (CSP) 檢查失敗。
  • 有一個待處理的取消連結要求。
  • 使用者在瀏覽器設定中停用 FedCM。

IdP 的中斷連線端點傳回回應時,RP 和 IdP 會在瀏覽器上中斷連線,並成功解決承諾。中斷連線端點的回應會指定已中斷連線帳戶的 ID。

從跨來源 iframe 呼叫 FedCM

如果上層頁框允許,就可以使用 identity-credentials-get 權限政策,從跨來源 iframe 中叫用 FedCM。方法是將 allow="identity-credentials-get" 屬性附加至 iframe 標記,如下所示:

<iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>

您可以在範例中查看實際運作情形。

或者,如果上層頁框要限制來源呼叫 FedCM,則可傳送含有允許來源清單的 Permissions-Policy 標頭。

Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")

如要進一步瞭解權限政策的運作方式,請參閱使用權限政策控管瀏覽器功能一文。