使用 FedCM 導入身分識別解決方案

FedCM (聯合憑證管理) 是一種隱私權保護方法,可用於聯合身分識別資訊服務 (例如「使用...登入」),讓使用者不必與身分識別資訊服務或網站分享個人資訊,即可登入網站。

FedCM 實作包含幾個核心步驟,適用於 IdP (Identity Provider) 和 RP (依賴方)。

IdPs 必須完成下列步驟才能實作 FedCM:

RP 需要完成下列步驟,才能在網站上啟用 FedCM:

將 FedCM 做為 IdP 導入

進一步瞭解在 IdP 端實作 FedCM 的步驟。

建立 well-known 檔案

為避免追蹤器濫用 API,您必須從 IdP 的 eTLD+1/.well-known/web-identity 提供 well-known 檔案。

已知檔案可包含下列屬性:

屬性 必填 說明
provider_urls 必填 IdP 設定檔路徑的陣列。如果指定 accounts_endpointlogin_url,系統會略過此屬性 (但仍是必要屬性)。
accounts_endpoint 建議使用,需要 login_url
帳戶端點的網址。只要每個設定檔都使用相同的 login_urlaccounts_endpoint 網址,即可支援多個設定。

注意:Chrome 132 以上版本支援此參數。
login_url 建議使用,需要 accounts_endpoint 使用者登入 IdP 的登入頁面網址。只要每個設定檔都使用相同的 login_urlaccounts_endpoint,即可支援多個設定。

注意:Chrome 132 以上版本支援此參數。

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

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

IdP 可在 well-known 檔案中指定 accounts_endpointlogin_url,以便支援多個 IdP 設定檔。
在下列情況下,這項功能會非常實用:

  • 身分提供者需要支援多種不同的測試和實際工作環境設定。
  • IdP 需要支援各個區域的不同設定 (例如 eu-idp.exampleus-idp.example)。

如要支援多個設定 (例如區分測試環境和實際工作環境),IdP 必須指定 accounts_endpointlogin_url

  {
    // This property is required, but will be ignored when IdP supports
    // multiple configs (when `accounts_endpoint` and `login_url` are
    // specified), as long as `accounts_endpoint` and `login_url` in
    // that config file match those in the well-known file.
    "provider_urls": [ "https://idp.example/fedcm.json" ],

    // Specify accounts_endpoint and login_url properties to support
    // multiple config files.
    // Note: The accounts_endpoint and login_url must be identical
    // across all config files. Otherwise,
    // the configurations won't be supported.
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }

建立 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;

RP 會將設定檔的網址傳遞至 FedCM API 呼叫,讓使用者登入:

  // Executed on RP's side:
  const credential = await navigator.credentials.get({
    identity: {
      context: 'signup',
      providers: [{
        // To allow users to sign in with an IdP using FedCM, RP specifies the IdP's config file URL:
        configURL: 'https://accounts.idp.example/fedcm.json',
        clientId: '********',
  });
  const { token } = credential;

瀏覽器會使用 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 回應的設定端點。JSON 包含下列屬性:

屬性 說明
accounts_endpoint (必填) 帳戶端點的網址。
accounts.include (選用) 自訂帳戶標籤字串,用於決定使用此設定檔時應傳回哪些帳戶,例如: "accounts": {"include": "developer"}
IdP 可以實作自訂帳戶標籤,如下所示:

舉例來說,IdP 會實作 "https://idp.example/developer-config.json" 設定檔,並指定 "accounts": {"include": "developer"}。IdP 也會在 帳戶端點中使用 labels 參數,為部分帳戶加上 "developer" 標籤。如果 RP 使用指定 "https://idp.example/developer-config.json" 設定檔的 navigator.credentials.get() 進行呼叫,系統只會傳回標示為 "developer" 的帳戶。
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 像素,在主動模式下則必須大於或等於 40 像素。
modes 物件,其中包含 FedCM UI 在不同模式下顯示方式的規格:
  • active
  • passive
modes.active 物件包含可在特定模式下自訂 FedCM 行為的屬性。modes.activemodes.passive 都包含以下參數:
  • supports_use_other_account:布林值,指出使用者是否可以使用與目前登入帳戶不同的帳戶登入 (如果 IdP 支援多個帳戶)。

注意:Chrome 132 以上版本支援「使用其他帳戶」功能和活動模式。
modes.passive

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

  {
    "accounts_endpoint": "/accounts.example",
    "client_metadata_endpoint": "/client_metadata.example",
    "id_assertion_endpoint": "/assertion.example",
    "disconnect_endpoint": "/disconnect.example",
    "login_url": "/login",
    // When RPs use this config file, only those accounts will be
    //returned that include `developer` label in the accounts endpoint.
    "accounts": {"include": "developer"},
    "modes": {
        "active": {
          "supports_use_other_account": true,
        }
    },
    "branding": {
      "background_color": "green",
      "color": "#FFEEAA",
      "icons": [{
        "url": "https://idp.example/icon.ico",
        "size": 25
      }]
    }
  }

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

IdP 端點
IdP 端點

使用其他帳戶

如果 IdP 支援多個帳戶或取代現有帳戶,使用者可以切換至與目前登入帳戶不同的帳戶。

如要讓使用者選擇其他帳戶,IdP 必須在設定檔中指定這項功能:

  {
    "accounts_endpoint" : "/accounts.example",
    "modes": {
      "active": {
        // Allow the user to choose other account (false by default)
        "supports_use_other_account": true
      }
      // "passive" mode can be configured separately
    }
  }

帳戶端點

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

瀏覽器傳送含有 SameSite=None 的 Cookie GET 要求,但沒有 client_id 參數、Origin 標頭或 Referer 標頭。這樣一來,IdP 就無法得知使用者嘗試登入哪個 RP。例如:

  GET /accounts.example 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(),藉此篩選帳戶。
labels (選用) 與帳戶相關聯的自訂帳戶標籤字串陣列。
IdP 可以實作自訂帳戶標籤,如下所示:
  • 在帳戶端點中指定帳戶標籤 (使用此 labels 參數)。
  • 為每個特定標籤建立設定檔

舉例來說,IdP 會實作已指定 "accounts": {"include": "developer"}https://idp.example/developer-config.json 設定檔。IdP 也會在 帳戶端點中使用 labels 參數,為部分帳戶加上 "developer" 標籤。如果 RP 呼叫 navigator.credentials.get() 時指定 https://idp.example/developer-config.json 設定檔,系統只會傳回標示為 "developer" 的帳戶。

自訂帳戶標籤與登入提示和網域提示不同,因為前者由 IdP 伺服器完全維護,而 RP 只會指定要使用的設定檔。

回應主體範例:

  {
    "accounts": [{
      "id": "1234",
      "given_name": "John",
      "name": "John Doe",
      "email": "john_doe@idp.example",
      "picture": "https://idp.example/profile/123",
      // Ids of those RPs where this account can be used
      "approved_clients": ["123", "456", "789"],
      // This account has 'login_hints`. When an RP calls `navigator.credentials.get()`
      // with a `loginHint` value specified, for example, `exampleHint`, only those
      // accounts will be shown to the user whose 'login_hints' array contains the `exampleHint`.
      "login_hints": ["demo1", "exampleHint"],
      // This account is labelled. IdP can implement a specific config file for a
      // label, for example, `https://idp.example/developer-config.json`. Like that
      // RPs can filter out accounts by calling `navigator.credentials.get()` with
      // `https://idp.example/developer-config.json` config file.
      "labels": ["hr", "developer"]
    }, {
      "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"],
      "domain_hints": ["@domain.example"]
    }]
  }

如果使用者未登入,請回應 HTTP 401 (未經授權)。

瀏覽器會使用傳回的帳戶清單,RP 無法使用。

ID 斷言端點

IdP 的 ID 斷言端點會針對已登入的使用者傳回斷言。當使用者使用 navigator.credentials.get() 呼叫登入 RP 網站時,瀏覽器會傳送 POST 要求,其中包含含有 SameSite=None 的 Cookie,以及 application/x-www-form-urlencoded 的內容類型,並將以下資訊傳送至此端點:

屬性 說明
client_id (必填) RP 的用戶端 ID。
account_id (必填) 登入使用者的專屬 ID。
disclosure_text_shown 結果為 "true""false" 的字串 (而非布林值)。在下列情況下,結果為 "false"
  • 如果 RP 的用戶端 ID 已納入 accounts 端點回應的 approved_clients 屬性清單,則系統不會顯示揭露文字。
  • 如果瀏覽器在過去未出現 approved_clients 時,就會觀察到註冊時刻,因此未顯示揭露文字。
  • 如果 fields 參數未包含一個或多個欄位 (「name」、「email」和「picture」),例如 fields=[ ]fields=['name', 'picture']。這項功能是為了與舊版 IdP 實作項目相容,因為舊版 IdP 實作項目會預期揭露聲明字串一律包含這三個欄位。
is_auto_selected 如果在 RP 上執行自動重新驗證is_auto_selected 會表示 "true"。否則為 "false"。這有助於支援更多安全性相關功能。舉例來說,有些使用者可能偏好更高的安全層級,這類層級需要在驗證時明確介入使用者。如果 IdP 收到的權杖要求未經過此類中介處理,則可能會以不同的方式處理要求。例如傳回錯誤代碼,讓 RP 可以再次使用 mediation: required 呼叫 FedCM API。
fields (選用) 字串陣列,用於指定 RP 需要 ID 提供者提供的使用者資訊 (「name」、「email」、「picture」)。
瀏覽器會傳送 fieldsdisclosure_text_showndisclosure_shown_for,列出 POST 要求中的指定欄位,如以下範例所示。

注意:Chrome 132 以上版本支援「Fields」參數。
params (選用) 任何可指定額外自訂鍵/值參數的有效 JSON 物件,例如:
  • scope:字串值,其中包含 RP 需要要求的其他權限,例如 "drive.readonly calendar.readonly"
  • nonce:RP 提供的隨機字串,用於確保系統針對此特定要求發出回應。防範重播攻擊。
  • 其他自訂鍵/值參數。
當瀏覽器傳送 POST 要求時,params 值會序列化為 JSON,然後以百分比編碼

注意:Chrome 132 以上版本支援 Parameters API。

HTTP 標頭範例:

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

  // disclosure_text_shown is set to 'false', as the 'name' field value is missing in 'fields' array
  // params value is serialized to JSON and then percent-encoded.
  account_id=123&client_id=client1234&disclosure_text_shown=false&is_auto_selected=true&params=%22%7B%5C%22nonce%5C%22%3A%5C%22nonce-value%5C%22%7D%22.%0D%0A4&disclosure_text_shown=true&fields=email,picture&disclosure_shown_for=email,picture

收到要求後,伺服器應:

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

身分提供者可以決定如何發出權杖。一般來說,權杖會使用帳戶 ID、用戶端 ID、發出者來源和 Nonce 等資訊進行簽署,以便 RP 驗證權杖是否為真。

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

屬性 說明
token 權杖是包含驗證相關宣告的字串。
continue_on 可啟用多步驟登入流程的重新導向網址。

瀏覽器會將傳回的權杖傳遞給 RP,以便 RP 驗證驗證。

  {
    // IdP can respond with a token to authenticate the user
    "token": "***********"
  }
繼續使用功能

IdP 可以在ID 斷言端點回應中提供重新導向網址,啟用多步驟登入流程。當 IdP 需要要求其他資訊或權限時,這項功能就很實用,例如:

  • 存取使用者伺服器端資源的權限。
  • 驗證聯絡資訊是否為最新資訊。
  • 家長監護。

ID 斷言端點可傳回 continue_on 屬性,其中包含 ID 斷言端點的絕對或相對路徑。

  {
    // In the id_assertion_endpoint, instead of returning a typical
    // "token" response, the IdP decides that it needs the user to
    // continue on a popup window:
    "continue_on": "https://idp.example/continue_on_url"
  }

如果回應包含 continue_on 參數,系統會開啟新的彈出式視窗,並將使用者導向指定的路徑。使用者與 continue_on 頁面互動後,IdP 應呼叫 IdentityProvider.resolve(),並將符記傳遞為引數,以便解析原始 navigator.credentials.get() 呼叫的承諾:

  document.getElementById('example-button').addEventListener('click', async () => {
    let accessToken = await fetch('/generate_access_token.cgi');
    // Closes the window and resolves the promise (that is still hanging
    // in the relying party's renderer) with the value that is passed.
    IdentityProvider.resolve(accessToken);
  });

瀏覽器會自動關閉彈出式視窗,並將權杖傳回給 API 呼叫端。一次性的 IdentityProvider.resolve() 呼叫是父項視窗 (RP) 和彈出式視窗 (IdP) 通訊的唯一方式。
如果使用者拒絕要求,IdP 可以呼叫 IdentityProvider.close() 關閉視窗。

  IdentityProvider.close();

接續 API 需要明確的使用者互動 (點擊) 才能運作。以下說明接續 API 如何搭配不同的中介模式運作:

  • 被動模式中:
    • mediation: 'optional' (預設):Continuation API 只會在使用者動作 (例如點選頁面或 FedCM UI 上的按鈕) 時運作。在沒有使用者手勢的情況下觸發自動重新驗證時,系統不會開啟彈出式視窗,且承諾會遭到拒絕。
    • mediation: 'required':一律要求使用者互動,因此 Continuation API 一律會運作。
  • 活動模式中:
    • 使用者必須啟用。Continuation API 相容。

如果使用者基於某些原因在彈出式視窗中變更帳戶 (例如,IdP 提供「使用其他帳戶」功能,或在委派案例中),則解析呼叫會採用可選的第二個引數,允許以下操作:

  IdentityProvider.resolve(token, {accountId: '1234');
傳回錯誤回應

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

  • 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"
    }
  }

自訂帳戶標籤

透過自訂帳戶標籤,IDP 可以為使用者帳戶加上標籤,而 RP 可以選擇只擷取具有特定標籤的帳戶,方法是指定該特定標籤的 configURL。當 RP 需要依據特定條件篩除帳戶時,這項功能就很實用,例如只顯示特定角色的帳戶,例如 "developer""hr"

您也可以使用網域提示登入提示功能,在 navigator.credentials.get() 呼叫中指定這兩項功能,以便進行類似的篩選。不過,自訂帳戶標籤可以透過指定設定檔來篩選使用者,這在使用多個 configURL 時特別實用。自訂帳戶標籤的另一個不同之處,在於這些標籤是由 IdP 伺服器提供,而非由 RP (例如登入或網域提示) 提供。

假設有個 ID 提供者想區分 "developer""hr" 帳戶,為達成這項目標,IdP 需要分別支援 "developer""hr" 的兩個 configURL:

  • 開發人員設定檔 https://idp.example/developer/fedcm.json"developer" 標籤,企業設定檔 https://idp.example/hr/fedcm.json 則有 "hr" 標籤,如下所示:
  // The developer config file at `https://idp.example/developer/fedcm.json`
  {
    "accounts_endpoint": "https://idp.example/accounts",
    "client_metadata_endpoint": "/client_metadata",
    "login_url": "https://idp.example/login",
    "id_assertion_endpoint": "/assertion",
    "accounts": {
      // Account label
      "include": "developer"
    }
  }
  // The hr config file at `https://idp.example/hr/fedcm.json`
  {
    "accounts_endpoint": "https://idp.example/accounts",
    "client_metadata_endpoint": "/client_metadata",
    "login_url": "https://idp.example/login",
    "id_assertion_endpoint": "/assertion",
    "accounts": {
      // Account label
      "include": "hr"
    }
  }
  • 在這種設定下,well-known 檔案應包含 accounts_endpointlogin_url,以便允許多個 configURL:
  {
    "provider_urls": [ "https://idp.example/fedcm.json" ],
    "accounts_endpoint": "https://idp.example/accounts",
    "login_url": "https://idp.example/login"
  }
  • 常見的 IdP 帳戶端點 (在本例中為 https://idp.example/accounts) 會傳回帳戶清單,其中包含 labels 屬性,並在每個帳戶的陣列中指派標籤:
  {
  "accounts": [{
    "id": "123",
    "given_name": "John",
    "name": "John Doe",
    "email": "john_doe@idp.example",
    "picture": "https://idp.example/profile/123",
    "labels": ["developer"]
    }], [{
    "id": "4567",
    "given_name": "Jane",
    "name": "Jane Doe",
    "email": "jane_doe@idp.example",
    "picture": "https://idp.example/profile/4567",
    "labels": ["hr"]
    }]
  }

如果 RP 想要允許 "hr" 使用者登入,可以在 navigator.credentials.get() 呼叫中指定 configURL https://idp.example/hr/fedcm.json

  let { token } = await navigator.credentials.get({
    identity: {
      providers: [{
        clientId: '1234',
        nonce: '234234',
        configURL: 'https://idp.example/hr/fedcm.json',
      },
    }
  });

因此,使用者只能使用 4567 的帳戶 ID 登入。瀏覽器會自動隱藏 123 的帳戶 ID,以免使用者提供的帳戶不受此網站上的 IdP 支援。

  • 標籤是字串。如果 labels 陣列或 include 欄位包含非字串的內容,系統會忽略該內容。
  • 如果 configURL 中未指定標籤,FedCM 帳戶選擇器會顯示所有帳戶。
  • 如果帳戶未指定標籤,只有在 configURL 也未指定標籤時,系統才會在帳戶選擇器中顯示該帳戶。
  • 如果在無主模式下,沒有任何帳戶與要求的標籤相符 (類似網域提示功能),FedCM 對話方塊會顯示登入提示,讓使用者登入 IdP 帳戶。在啟用模式下,系統會直接開啟登入彈出式視窗。

中斷連線端點

透過叫用 IdentityCredential.disconnect(),瀏覽器會傳送跨來源 POST 要求,其中含有含有 SameSite=None 的 Cookie,以及 application/x-www-form-urlencoded 的內容類型,並將這些資訊傳送至這個斷線端點:

屬性 說明
account_hint IdP 帳戶的提示。
client_id RP 的用戶端 ID。
  POST /disconnect.example 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 標頭與 client_id 判定的 RP 來源進行比對。如果不相符,請拒絕。
  4. account_hint 與已登入帳戶的 ID 比對。
  5. 將使用者帳戶與 RP 斷開連結。
  6. 以 JSON 格式回應瀏覽器,提供已識別的使用者帳戶資訊。

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

  {
    "account_id": "account456"
  }

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

用戶端中繼資料端點

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

瀏覽器會使用 client_id navigator.credentials.get 傳送 GET 要求,但不使用 Cookie。例如:

  GET /client_metadata.example?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 (非必要) RP 隱私權政策網址。
terms_of_service_url (非必要) RP 服務條款網址。
icons (非必要) 物件陣列,例如 [{ "url": "https://rp.example/rp-icon.ico", "size": 40}]

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

  {
    "privacy_policy_url": "https://rp.example/privacy_policy.html",
    "terms_of_service_url": "https://rp.example/terms_of_service.html",
    "icons": [{
          "url": "https://rp.example/rp-icon.ico",
          "size": 40
      }]
  }

瀏覽器會使用已傳回的用戶端中繼資料,RP 則無法使用。

登入網址

這個端點可讓使用者登入 IdP。

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

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

A
FedCM 對話方塊建議登入 IdP。

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

FedCM 對話方塊範例。
點選「登入 IdP」按鈕後顯示的對話方塊範例。

對話方塊是含有第一方 Cookie 的一般瀏覽器視窗。對話方塊中的所有事件都由 IdP 處理,而且沒有可用來向 RP 頁面提出跨來源通訊要求的視窗句柄。使用者登入後,IdP 應:

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

通知瀏覽器使用者的登入狀態

登入狀態 API 是一種機制,可讓網站 (尤其是 IdP) 向瀏覽器通知使用者在 IdP 上的登入狀態。有了這個 API,瀏覽器就能減少對 IdP 的不必要要求,並減輕潛在的時間攻擊

當使用者登入 IdP 或登出所有 IdP 帳戶時,IdP 可以透過傳送 HTTP 標頭或呼叫 JavaScript API,向瀏覽器傳送使用者的登入狀態。對於每個 IdP (以其設定網址識別),瀏覽器會保留一個三態變數,代表登入狀態,可能的值如下:

  • logged-in
  • logged-out
  • unknown (預設)
登入狀態 說明
logged-in 當使用者的登入狀態設為 logged-in 時,呼叫 FedCM 的 RP 會向 IdP 的帳戶端點提出要求,並在 FedCM 對話方塊中向使用者顯示可用的帳戶。
logged-out 如果使用者的登入狀態為 logged-out,則呼叫 FedCM 會在未向 IdP 的帳戶端點提出要求的情況下,以靜默方式失敗。
unknown (預設) unknown 狀態會在 IdP 使用登入狀態 API 傳送信號之前設定。狀態為 unknown 時,瀏覽器會向 IdP 的帳戶端點提出要求,並根據帳戶端點的回應更新狀態。

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

  Set-Login: logged-in

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

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

使用者的登入狀態會設為 logged-in

如要指出使用者已登出所有帳戶,請在頂層導覽中傳送 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

unknown 狀態會在 IdP 使用登入狀態 API 傳送信號之前設定。瀏覽器會向 IdP 的帳戶端點發出要求,並根據帳戶端點的回應更新狀態:

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

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

即使 IdP 持續向瀏覽器通知使用者的登入狀態,但在工作階段到期時,兩者可能會不同步。當登入狀態為 logged-in 時,瀏覽器會嘗試將憑證要求傳送至帳戶端點,但由於工作階段不再可用,因此伺服器不會傳回任何帳戶。在這種情況下,瀏覽器可以透過彈出式視窗,讓使用者以動態方式登入 IdP

將 FedCM 做為 RP 導入

取得 IdP 設定和端點後,RP 即可呼叫 navigator.credentials.get(),要求允許使用者透過 IdP 登入 RP。

在呼叫 API 之前,您需要確認 FedCM 可在使用者的瀏覽器上使用。如要檢查 FedCM 是否可用,請在 FedCM 實作項目中包裝以下程式碼:

  if ('IdentityCredential' in window) {
    // If the feature is available, take action
  } else {
    // FedCM is not supported, use a different identity solution
  }

如要讓使用者透過 FedCM 在 RP 上登入 IdP,RP 可以呼叫 navigator.credentials.get(),例如:

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

背景資訊屬性

透過選用的 context 屬性,RP 可以修改 FedCM 對話方塊 UI 中的字串 (例如「Sign in to rp.example…」和「Use idp.example…」),以便配合預先定義的驗證內容。context 屬性可包含下列值:

  • signin (預設)
  • signup
  • use
圖表說明 FedCM 對話方塊的 UI 元件:左上方顯示圖示。圖示右側的內容元件會顯示「使用 IdP 登入 RP」訊息。底部是「Continue」按鈕,內含自訂文字和背景顏色。
如何將品牌資訊套用至 FedCM 對話方塊

舉例來說,將 context 設為 use 會產生以下訊息:

FedCM 對話方塊顯示自訂的內容訊息:FedCM 不再顯示「Sign in」(登入),而是顯示「Use」(使用) FedCM。
FedCM 對話方塊顯示自訂的背景訊息。

瀏覽器會根據帳戶清單端點回應中是否存在 approved_clients,以不同方式處理註冊和登入用途。如果使用者已註冊 RP,瀏覽器就不會顯示「To continue with ....」的揭露資訊文字。
providers 屬性會採用 IdentityProvider 物件的陣列,其中包含下列屬性:

Providers 屬性

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

屬性 說明
configURL (必填) IdP 設定檔的完整路徑。
clientId (必填) 由 IdP 核發的 RP 用戶端 ID。
nonce (非必要) 隨機字串,可確保系統針對這項特定要求發出回應。防範重播攻擊。
loginHint (非必要) 指定 帳戶端點提供的 login_hints 值之一,FedCM 對話方塊就會依序顯示指定帳戶。
domainHint (非必要) 指定 帳戶端點提供的 domain_hints 值之一,FedCM 對話方塊就會依指定帳戶顯示。
mode (非必要) 指定 FedCM 使用者介面模式的字串。可為下列其中一個值:
  • "active":FedCM 提示必須由使用者互動 (例如按下按鈕) 啟動。
  • "passive":FedCM 提示會在沒有使用者直接互動情況下啟動。
請參閱總覽頁面,進一步瞭解主動模式和被動模式的差異。

注意:Chrome 132 以上版本支援 mode 參數。
fields (非必要) 字串陣列,用於指定 RP 需要 ID 提供者提供的使用者資訊 (「name」、「email」、「picture」)。
注意:Chrome 132 以上版本支援 Field API。
parameters (非必要) 可指定其他鍵/值參數的自訂物件:
  • scope:字串值,其中包含 RP 需要要求的其他權限,例如 "drive.readonly calendar.readonly"
  • nonce:隨機字串,可確保系統針對此特定要求發出回應。防範重播攻擊。
  • 其他自訂鍵/值參數。

注意:Chrome 132 以上版本支援 parameters

正常模式

FedCM 支援不同的使用者體驗模式設定。無主動模式是預設模式,開發人員不需要設定。

如何在啟用模式下使用 FedCM:

  1. 檢查使用者瀏覽器中是否支援這項功能。
  2. 使用暫時性使用者手勢 (例如按一下按鈕) 叫用 API。
  3. mode 參數傳遞至 API 呼叫:
  let supportsFedCmMode = false;
  try {
    navigator.credentials.get({
      identity: Object.defineProperty(
        // Check if this Chrome version supports the Mode API.
        {}, 'mode', {
          get: function () { supportsFedCmMode = true; }
        }
      )
    });
  } catch(e) {}

  if (supportsFedCmMode) {
    // The button mode is supported. Call the API with mode property:
    return await navigator.credentials.get({
      identity: {
        providers: [{
          configURL: 'https://idp.example/config.json',
          clientId: '123',
        }],
        // The 'mode' value defines the UX mode of FedCM.
        // - 'active': Must be initiated by user interaction (e.g., clicking a button).
        // - 'passive': Can be initiated without direct user interaction.
        mode: 'active'
      }
    });
  }

使用中模式的自訂圖示

在啟用模式下,IdP 可直接在用戶端中繼資料端點回應中加入 RP 的官方標誌圖示。RP 必須事先提供品牌資料。

從跨來源 iframe 中呼叫 FedCM

如果父項框架允許,您可以使用 identity-credentials-get 權限政策,從跨來源 iframe 內叫用 FedCM。如要這麼做,請在 iframe 代碼中附加 allow="identity-credentials-get" 屬性,如下所示:

  <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")

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

Login Hint API

使用者可以透過登入提示,讓 RP 建議使用者應登入哪個帳戶。對於不確定自己先前使用哪個帳戶的使用者,這項功能可協助他們重新驗證。

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

  return await navigator.credentials.get({
    identity: {
      providers: [{
        configURL: 'https://idp.example/manifest.json',
        clientId: '123',
        // Accounts endpoint can specify a 'login_hints' array for an account.
        // When RP specifies a 'exampleHint' value, only those accounts will be
        // shown to the user whose 'login_hints' array contains the 'exampleHint'
        // value
        loginHint : 'exampleHint'
      }]
    }
  });

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

Domain Hint API

供應商可以選擇只顯示與特定網域相關聯的帳戶。這對受限於公司網域的 RP 來說相當實用。

如要只顯示特定網域帳戶,RP 應使用 domainHint 屬性搭配 帳戶清單端點擷取的 domain_hints 值之一,呼叫 navigator.credentials.get(),如以下程式碼範例所示:

  return await navigator.credentials.get({
    identity: {
      providers: [{
        configURL: 'https://idp.example/manifest.json',
        clientId: 'abc',
        // Accounts endpoint can specify a 'domain_hints' array for an account.
        // When RP specifies a '@domain.example' value, only those accounts will be
        // shown to the user whose 'domain_hints' array contains the
        // '@domain.example' value
        domainHint : '@domain.example'
      }]
    }
  });

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

當系統找不到與網域相符的帳戶時,登入提示的範例。
當沒有帳戶與 domainHint 相符時的登入提示範例。

自訂參數

自訂參數功能可讓 RP 向ID 斷言端點提供額外的鍵/值參數。透過 Parameters API,RP 可以將額外參數傳遞至 IdP,要求基本登入以外的資源權限。在以下情況下,傳遞額外參數可能會很有幫助:

  • 接受方需要動態要求 ID 提供者具備的其他權限,例如帳單地址或日曆存取權。使用者可以透過使用「繼續使用」功能啟動的 IdP 控管使用者體驗流程授予這些權限,IdP 就會分享這項資訊。

如要使用 API,RP 會將參數新增至 params 屬性,做為 navigator.credentials.get() 呼叫中的物件:

  let {token} = await navigator.credentials.get({
    identity: {
      providers: [{
        clientId: '1234',
        configURL: 'https://idp.example/fedcm.json',
        // Key/value pairs that need to be passed from the
        // RP to the IdP but that don't really play any role with
        // the browser.
        params: {
          IDP_SPECIFIC_PARAM: '1',
          foo: 'BAR'
        }
      },
    }
  });

瀏覽器會自動將這項資訊轉譯為 POST 要求,並將參數設為單一網址編碼 JSON 序列化物件,傳送至 IdP:

  // The assertion endpoint is drawn from the config file
  POST /fedcm_assertion_endpoint HTTP/1.1
  Host: idp.example
  Origin: https://rp.example/
  Content-Type: application/x-www-form-urlencoded
  Cookie: 0x23223
  Sec-Fetch-Dest: webidentity

  // params are translated into urlencoded version of `{"IDP_SPECIFIC_PARAM":"1","foo":"bar"}`
  account_id=123&client_id=client1234&params=%22%7B%5C%22IDP_SPECIFIC_PARAM%5C%22%3A1%2C%5C%22foo%5C%22%3A%5C%22BAR%5C%22%7D%22.

如果 RP 需要任何額外權限,IdP 可以提供重新導向連結。例如在 node.js 中:

  if (rpRequestsPermissions) {
    // Response with a URL if the RP requests additional permissions
    return res.json({
      continue_on: '/example-redirect',
    });
  }

欄位

RP 可以指定 ID 方需要提供的使用者資訊 (姓名、電子郵件地址和個人資料相片的任意組合)。要求的資訊會列入 FedCM 對話方塊的揭露 UI 中。如果使用者選擇登入,系統會顯示訊息,通知使用者 idp.example 會將要求的資訊提供給 rp.example

FedCM 活動模式對話方塊顯示揭露訊息。如要繼續,身分識別提供者會將使用者的電子郵件地址和個人資料相片提供給網站。
在啟用模式下顯示的揭露訊息:RP 要求 IdP 只分享使用者的電子郵件地址和個人資料相片。

如要使用「欄位」功能,RP 應在 navigator.credentials.get() 呼叫中新增 fields 陣列。這些欄位可包含 nameemailpicture 的任何排列組合。日後可擴充至包含更多值。含有 fields 的請求如下所示:

  let { token } = await navigator.credentials.get({
    identity: {
      providers: [{
        // RP requests the IdP to share only user email and profile picture
        fields: [ 'email', 'picture'],
        clientId: '1234',
        configURL: 'https://idp.example/fedcm.json',

      },
    }
  });

瀏覽器會自動將其轉譯為 HTTP 要求,並傳送至包含 RP 指定 fields 參數的 ID 斷言端點,其中包含瀏覽器在 disclosure_shown_for 參數中向使用者揭露的欄位。為了確保向後相容性,如果瀏覽器顯示揭露文字,且要求的欄位包含 所有三個欄位'name''email''picture',瀏覽器也會傳送 disclosure_text_shown=true

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

  // The RP only requested to share email and picture. The browser will send `disclosure_text_shown=false`, as the 'name' field value is missing
  account_id=123&client_id=client1234&disclosure_text_shown=false&fields=email,picture&disclosure_shown_for=email,picture

如果 fields 是空陣列,使用者代理程式會略過揭露 UI。

FedCM 待命模式對話方塊,不會顯示揭露資訊的 UI 訊息。
在被動模式中不會顯示揭露訊息。在按鈕流程中,系統會完全略過揭露事項 UI。

即使帳戶端點的回應不含與 approved_clients 中的 RP 相符的用戶端 ID,也會發生這種情況。

在這種情況下,傳送至 ID 斷言端點disclosure_text_shown 在 HTTP 主體中為 false:

  POST /id_assertion_endpoint HTTP/1.1
  Host: 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=234234&disclosure_text_shown=false

顯示錯誤訊息

有時,IdP 可能會基於正當理由而無法發出權杖,例如用戶端未經授權,或伺服器暫時無法使用。如果 IdP 傳回「錯誤」回應,RP 可以擷取該回應,而 Chrome 可以顯示瀏覽器 UI,並顯示 IdP 提供的錯誤資訊,以便通知使用者。

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 登入對話方塊中的「以...身分繼續」按鈕,建立帳戶或登入 RP 網站。

雖然在使用者建立聯合帳戶以防追蹤 (這是 FedCM 的主要目標之一) 之前,明確的使用者體驗是合理的,但在使用者完成這項操作後,再要求他們明確確認這項操作,就沒有任何隱私權或安全性好處。因為使用者已授權允許 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':一律需要仲裁才能繼續,例如按一下 UI 上的「繼續」按鈕。如果您希望使用者每次需要驗證時都必須明確授予權限,請選擇這個選項。
  • 'silent':盡可能自動重新授權,如果無法自動重新授權,則在未要求中介服務的情況下,以靜默方式失敗。建議您在專屬登入頁面以外,但希望使用者保持登入狀態的網頁上選取這個選項,例如運送網站的商品頁面,或新聞網站的文章頁面。
  • 'conditional':用於 WebAuthn,目前不適用於 FedCM。

在這個呼叫中,系統會在下列情況下自動重新授權:

在符合這些條件時,只要叫用 FedCM navigator.credentials.get(),系統就會嘗試自動重新驗證使用者。

mediation: optional 時,自動重新驗證可能會因只有瀏覽器知道的原因而無法使用;RP 可以檢查 isAutoSelected 屬性,確認是否已執行自動重新驗證。

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

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

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

在使用者登出後立即自動重新驗證,並不會帶來良好的使用者體驗。因此,FedCM 會在自動重新授權後設有 10 分鐘的靜默期,以防發生這種行為。也就是說,除非使用者在 10 分鐘內重新登入,否則自動重新授權的情況最多會發生 10 分鐘一次。當使用者明確登出 RP (例如點選登出按鈕),RP 應呼叫 navigator.credentials.preventSilentAccess(),明確要求瀏覽器停用自動重新授權。

  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,以及用於斷開 IdP 的 accountHint。只要斷開連結端點可識別帳戶,帳戶提示可以是任意字串,例如電子郵件地址或使用者 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。