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

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

取消关联 API

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

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

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

断开 IdP 与 RP 之间的连接

如果用户之前通过 FedCM 使用 IdP 登录了 RP,浏览器会在本地将该关系记忆为已关联账号的列表。RP 可以通过调用 IdentityCredential.disconnect() 函数来发起断开连接。此函数可以从顶级 RP 帧调用。RP 需要传递 configURL(它在 IdP 下使用的 clientId)和 accountHint,以便断开 IdP 的连接。账号提示可以是任意字符串,只要断开连接端点可以识别该账号,例如电子邮件地址或用户 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。不过,由于 well-known 文件必须放置在 IdP 服务器的 eTLD+1 的根目录下,因此它必须位于 idp.example/.well-known/web-identity 且是生产服务器。由于开发者在开发过程中不一定能够将文件放置在生产环境中,因此无法测试 FedCM。

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

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

以前,Chrome 只允许在请求与所有祖先实体的同源时设置登录状态(例如,使用 Set-Login: logged-in 标头)。这阻止了通过 same-site 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 响应标头设置登录状态。