FedCM 更新:解除 API 和两项更新的关联

从 Chrome 122 开始,适用于 Federated Credential Management API (FedCM)Disconnect API 已推出。借助 Disconnect API,依赖方无需依赖第三方 Cookie,即可将其用户与身份提供方的账号断开关联。此外,FedCM 的同一网站处理方式也进行了一些更新。

Disconnect API

当用户通过身份联合在依赖方(RP,即使用身份提供商进行身份验证的网站)上创建账号时,身份提供商(IdP,即向其他方提供身份验证和账号信息的服务)通常会在其服务器上记录连接。通过存储的连接,IdP 可以跟踪用户已登录的 RP,并优化用户体验。例如,为了在用户日后返回 RP 时获得更好的体验,系统会将具有 IdP 的用户账号视为回访账号,从而支持自动重新身份验证和显示所用账号的个性化按钮等功能。

有时,IdP 会提供 API 来解除账号与 RP 的关联。不过,断开连接流程需要经过身份验证,并且需要 IdP Cookie。在没有第三方 Cookie 的世界中,当用户访问 RP 时,RP 无法使用浏览器 API 与 IdP 断开连接。由于同一 IdP 可能有多个账号与给定 RP 相关联,因此断开连接流程需要知道要断开连接的账号。

借助 Disconnect API,用户可以通过向指定端点发送信号,在浏览器和 IdP 服务器上将 IdP 账号与 RP 断开连接。用户需要使用联合凭据管理 API (FedCM) 完成身份联合。用户断开连接后,下次尝试使用 IdP 登录 RP 时,系统会将其视为新用户。

断开 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。此 promise 可能会因以下原因抛出异常:

  • 用户尚未通过 FedCM 使用 IdP 登录 RP。
  • 从不含 FedCM 权限政策的 iframe 中调用 API。
  • config网址 无效或缺少断开连接端点。
  • 内容安全政策 (CSP) 检查失败。
  • 有一个待处理的解除关联请求。
  • 用户已在浏览器设置中停用 FedCM。

身份提供方的断开连接端点返回响应时,浏览器上的 RP 和 IdP 会断开连接,并且 Promise 会解析。要解除关联的用户账号在解除关联端点的响应中指定。

设置 IdP 配置文件

为了支持 Disconnect API,IdP 必须支持断开连接端点,并在其 IdP 配置文件中提供 disconnect_endpoint 属性及其路径。

{
  "accounts_endpoint": "/accounts",
  "id_assertion_endpoint": "/assertion",
  ...
  "disconnect_endpoint: "/disconnect"
}

在解除关联端点上解除账号关联

通过调用 IdentityCredential.disconnect(),浏览器会向此断开连接端点发送包含 Cookie 和内容类型为 application/x-www-form-urlencoded 的跨源 POST 请求,其中包含以下信息:

属性 说明
account_hint IdP 账号的提示。
client_id RP 的客户端标识符。
POST /disconnect 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

收到请求后,IdP 服务器应:

  1. 使用 CORS(跨源资源共享)响应请求。
  2. 验证请求是否包含 Sec-Fetch-Dest: webidentity HTTP 标头。
  3. Origin 标头与由 client_id 确定的 RP 源进行匹配。如果不匹配,请拒绝。
  4. 找到与 account_hint 匹配的账号。
  5. 将用户账号从 RP 关联账号列表中解除关联。
  6. 以 JSON 格式向浏览器响应已识别用户的 account_id

响应 JSON 载荷示例如下:

{
  "account_id": "account456"
}

如果 IdP 希望浏览器改为解除与 RP 关联的所有账号的关联,请传递与任何账号 ID 都不匹配的字符串,例如 "*"

现在,如果 RP 和 IdP 位于同一网站上,系统会跳过检查 /.well-known/web-identity

开发 FedCM 系统时,测试或预演 RP 服务器网域可以是生产 IdP 服务器的子网域。例如,生产 IdP 服务器位于 idp.example,而暂存 RP 服务器和暂存 IdP 服务器位于 staging.idp.example。不过,由于知名文件必须放置在 IdP 服务器的 eTLD+1 的根目录下,因此它必须位于 idp.example/.well-known/web-identity 且是生产服务器。由于开发者在开发过程中不一定能够将文件放置在生产环境中,因此无法测试 FedCM。

从 Chrome 122 开始,如果 RP 网域和 IdP 网域相同,Chrome 会跳过检查已知文件。这样,开发者便可以在这种情况下进行测试。

子资源现在可以设置同一网站登录状态

以前,Chrome 仅允许在请求与所有祖先具有相同来源时设置登录状态(例如,使用 Set-Login: logged-in 标头)。这会阻止通过设置登录状态的同一网站 fetch() 请求进行登录。

例如,假设有一个网站允许用户在 idp.example 上输入用户名和密码,但凭据会使用 fetch() 发布到 login.idp.example。由于这两个网域是跨源且位于同一网站上,因此无法使用 Login Status API 将登录状态记录到浏览器。

通过这项变更,我们放宽了对 Login Status API 与所有祖先网页位于同一网站的要求,使上述示例能够使用 HTTP 标头 (Set-Login: logged-in) 设置 login.idp.example 的登录状态。

摘要

通过使用 Disconnect API,FedCM 现在可以将 RP 与 IdP 断开连接,而无需依赖第三方 Cookie。为此,请在 RP 上调用 IdentityCredential.disconnect()。借助此函数,浏览器会向 IdP 的断开连接端点发送请求,以便 IdP 先在服务器上终止连接,然后再在浏览器上终止连接。

我们已宣布,出于测试目的,当 RP 和 IdP 位于同一网站时,系统会跳过 /.well-known/web-identity 检查。此外,现在可以通过同网站 IdP 子资源中的 HTTP 响应标头设置登录状态。