FedCM 更新:Login Status API、Error API 和 Auto-selected Flag API

Chrome 120 为 FedCM 提供了 Login Status API。Login Status API(以前称为 IdP Sign-in Status API)允许网站(尤其是身份提供方)在用户登录和退出时向浏览器发出信号。FedCM 使用此信号来解决静默计时攻击问题,并因此让 FedCM 无需使用第三方 Cookie 即可运行此更新解决了我们之前在 FedCM 原始意向 (FedCM) 中发现的最后一项向后不兼容的更改,属于我们的工作范围

虽然 Login Status API 改进了 Privacy 属性和易用性,但这项变更一旦推出便不向后兼容。如果您已有 FedCM 实现,请务必按照以下说明进行更新。

此外,Chrome 还提供两项新的联合凭据管理 (FedCM) 功能:

  • Error API:当用户的登录尝试失败时,根据来自 ID 断言端点的服务器响应(如果有)通过原生界面通知用户。
  • Auto-Selected Flag API:如果流程中自动选择了凭据,则通知身份提供方 (IdP) 和依赖方 (RP)。

Login Status API

Login Status API 是一种机制,可供网站(尤其是 IdP)告知浏览器用户在 IdP 上的登录状态。借助此 API,浏览器可以减少向 IdP 发送的不必要请求并缓解潜在的计时攻击。

将用户的登录状态告知浏览器

当用户在 IdP 上登录或退出其所有 IdP 帐号时,IdP 可以通过以下两种方式向浏览器告知用户的登录状态:发送 HTTP 标头或调用 JavaScript API。对于每个 IdP(由其配置网址标识),浏览器都会保留一个表示登录状态的三态变量,可能的值包括 logged-inlogged-outunknown。默认状态为 unknown

如需表明用户已登录,请在顶级导航或同源子资源请求中发送 Set-Login: logged-in HTTP 标头:

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 标头:

Set-Login: logged-out

或者,从 IdP 来源调用 JavaScript API navigator.login.setStatus('logged-out')

navigator.login.setStatus('logged-out');

此类调用会将用户的登录状态记录为 logged-out。当用户登录状态为 logged-out 时,调用 FedCM 会静默失败,而不会向 IdP 的帐号列表端点发出请求。

unknown 状态在 IdP 发送信号之前使用 Login Status API 设置。我们引入此状态是为了更好地进行转换,因为用户可能已经在我们推出此 API 时登录了 IdP。在首次调用 FedCM 时,IdP 可能没有机会向浏览器发出信号。在这种情况下,我们会向 IdP 的帐号列表端点发出请求,并根据来自帐号列表端点的响应更新状态:

  • 如果端点返回活跃帐号的列表,请将状态更新为 logged-in,并打开 FedCM 对话框以显示这些帐号。
  • 如果端点未返回任何帐号,请将状态更新为 logged-out 并使 FedCM 调用失败。

如果用户会话过期,该怎么办?让用户通过动态登录流程登录!

即使 IdP 不断通知用户的浏览器登录状态,状态也可能不同步,例如当会话过期时。当登录状态为 logged-in 时,浏览器会尝试向帐号列表端点发送存储了凭据的请求,但由于会话不再可用,服务器不会返回任何帐号。在这种情况下,浏览器可以通过对话框窗口动态地让用户登录 IdP。

FedCM 对话框会显示建议登录的消息,如下图所示。

建议登录 IdP 的 FedCM 对话框。
一个建议登录 IdP 的 FedCM 对话框。

当用户点击继续按钮时,浏览器会打开 IdP 登录页面的对话框。

示例对话框。
点击“登录 IdP”按钮后显示的示例对话框。

登录页面网址在 IdP 配置文件中使用 login_url 指定。

{
  "accounts_endpoint": "/auth/accounts",
  "client_metadata_endpoint": "/auth/metadata",
  "id_assertion_endpoint": "/auth/idtokens",
  "login_url": "/login"
  }
}

该对话框是包含第一方 Cookie 的常规浏览器窗口。对话框中发生的情况由 IdP 决定,没有可用于向 RP 页面发出跨源通信请求的窗口句柄。用户登录后,IdP 应执行以下操作:

  • 发送 Set-Login: logged-in 标头或调用 navigator.login.setStatus("logged-in") API,以通知浏览器用户已登录。
  • 调用 IdentityProvider.close() 以关闭对话框。
用户在使用 FedCM 登录 IdP 后登录 RP。
用户在使用 FedCM 登录 IdP 后登录 RP。

您可以在我们的演示中试用 Login Status API 行为。

  1. 点按转到 IdP 并登录按钮。
  2. 使用任意帐号登录。
  3. 帐号状态下拉列表中选择会话已过期
  4. 更新个人信息按钮。
  5. 点按 Visit the RP to try FedCM(访问 RP 以尝试 FedCM)按钮。

您应该能够通过模块行为观察登录 IdP 的情况。

错误 API

当 Chrome 向 ID 断言端点发送请求时(例如,当用户点击 FedCM 界面上的 Continue as 按钮时,或触发自动重新身份验证时),IdP 可能会因正当原因而无法颁发令牌。 例如,如果客户端未经授权,则服务器暂时不可用,等等。目前,如果发生此类错误,Chrome 会以静默方式使请求失败,并且仅通过拒绝 promise 来通知 RP。

借助 Error API,Chrome 会使用 IdP 提供的错误信息显示原生界面,从而通知用户。

显示用户登录尝试失败后显示的错误消息的 FedCM 对话框。该字符串与错误类型相关联。
显示用户登录尝试失败后显示的错误消息的 FedCM 对话框。该字符串与错误类型相关联。

IdP HTTP API

id_assertion_endpoint 响应中,如果可以根据请求颁发令牌,则 IdP 可以将令牌返回给浏览器。在此方案中,如果无法颁发令牌,IdP 可以返回“错误”响应,其中包含两个新的可选字段:

  1. code
  2. url
// id_assertion_endpoint response
{
  "error": {
     "code": "access_denied",
     "url": "https://idp.example/error?type=access_denied"
  }
}

对于代码,IdP 可以从 OAuth 2.0 指定错误列表 [invalid_requestunauthorized_clientaccess_deniedserver_errortemporarily_unavailable] 中选择一个已知错误,也可以使用任意字符串。如果是后者,Chrome 会使用一般错误消息呈现错误界面,并将代码传递给 RP。

对于 url,它会标识包含错误相关信息的人类可读网页,以便向用户提供有关错误的更多信息。此字段对用户很有用,因为浏览器无法在原生界面中提供丰富的错误消息。例如,后续步骤链接、客户服务联系信息等。如果用户想要详细了解错误详情及解决方法,可以从浏览器界面访问所提供的页面,获取更多详情。该网址必须与 IdP configURL 位于同一网站。

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;
}

自动选择标记 API

mediation: optional 是 Credential Management API 中的默认用户中介行为,它会尽可能触发自动重新进行身份验证。但是,由于只有浏览器知道原因,自动重新身份验证可能不可用;当自动重新身份验证不可用时,系统可能会提示用户通过显式用户中介进行登录,该流程具有不同的属性。

  • 从 API 调用方的角度来看,当他们收到 ID 令牌时,无法得知这是否是由自动重新身份验证流程引起的。这使得他们很难评估 API 性能并相应地改善用户体验。
  • 从 IdP 的角度来看,他们同样无法判断是否进行了自动重新身份验证,以便评估性能。此外,是否涉及明确的用户中介可以帮助他们支持更多与安全相关的功能。例如,某些用户可能更喜欢更高的安全层级,这要求身份验证中需要明确的用户中介。如果 IdP 在没有使用此类中介的情况下收到令牌请求,他们可能会以不同的方式处理该请求。例如,返回错误代码,以便 RP 可以使用 mediation: required 再次调用 FedCM API。

因此,提供自动重新身份验证流程的可见性对开发者有益。

使用 Auto-selected Flag API,Chrome 会在每次发生自动重新身份验证或发生明确的中介时,与 IdP 和 RP 分享是否通过点按继续以身份登录按钮获得了明确的用户权限。只有在获得 IdP/RP 通信的用户权限后,才会进行共享。

IdP 共享

为了将信息分享给 IdP 的用户权限后,Chrome 会在发送给 id_assertion_endpointPOST 请求中添加 is_auto_selected=true

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

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

RP 共享

浏览器可以通过 IdentityCredential 将信息分享给 isAutoSelected 中的 RP:

const cred = await navigator.credentials.get({
  identity: {
    providers: [{
      configURL: 'https://idp.example/manifest.json',
      clientId: '1234'
    }]
  }
});

if (cred.isAutoSelected !== undefined) {
  const isAutoSelected = cred.isAutoSelected;
}

互动和分享反馈

如果您有反馈或在测试期间遇到任何问题,可以通过 crbug.com 分享。

照片提供者:Unsplash 用户 Girl with red hat