Chrome 120 将为 FedCM 提供 Login Status API。 借助 Login Status API(以前称为 IdP Sign-in Status API),网站(尤其是身份提供方)可以在用户登录和退出时向浏览器发送信号。FedCM 使用此信号来解决静默计时攻击问题,从而允许 FedCM 完全无需第三方 Cookie 即可运行。在工作范围内,此更新解决了我们之前在 FedCM 的原始发货 intent 中发现的最后一个向后不兼容的更改。
虽然 Login Status API 可以改善隐私属性和易用性,但发布后,它将与旧版不兼容。如果您已实现 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-in
、logged-out
和 unknown
。默认状态为 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 的账号列表端点发出请求。
在 IDP 使用 Login Status API 发送信号之前,系统会设置 unknown
状态。我们引入此状态是为了更好地实现过渡,因为在我们发布此 API 时,用户可能已登录 IdP。在首次调用 FedCM 时,IdP 可能没有机会向浏览器发出此信号。在本例中,我们向 IdP 的账号列表端点发出请求,并根据账号列表端点的响应更新状态:
- 如果端点返回有效账号列表,请将状态更新为
logged-in
,然后打开 FedCM 对话框以显示这些账号。 - 如果端点未返回任何账号,请将状态更新为
logged-out
并使 FedCM 调用失败。
如果用户会话过期,会怎么样?让用户通过动态登录流程登录!
即使 IdP 会持续向浏览器告知用户的登录状态,但状态也可能会不同步,例如在会话过期时。当登录状态为 logged-in
时,浏览器会尝试向账号列表端点发送包含凭据的请求,但由于会话不再可用,服务器不会返回任何账号。在这种情况下,浏览器可以通过对话框窗口动态让用户登录 IdP。
FedCM 对话框会显示一条提示登录的消息,如下图所示。

当用户点击 Continue 按钮时,浏览器会打开一个对话框,显示 IDP 的登录页面。

登录页面网址是使用 login_url
在 IdP 配置文件中指定的。
{
"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()
以关闭对话框。

您可以在我们的演示中试用 Login Status API 行为。
- 点按前往身份提供方并登录按钮。
- 使用任意账号登录。
- 从账号状态下拉菜单中选择会话已过期。
- 按更新个人信息按钮。
- 点按访问 RP 以试用 FedCM 按钮。
您应该能够通过模块行为观察对 IdP 的登录。
Error API
当 Chrome 向身份断言端点发送请求时(例如,当用户点击 FedCM 界面上的继续按钮或触发自动重新身份验证时),IdP 可能无法出于合法原因签发令牌。例如,如果客户端未经授权、服务器暂时不可用等。目前,如果发生此类错误,Chrome 会静默失败请求,并且只会通过拒绝 promise 来通知 RP。
借助 Error API,Chrome 会显示包含 IdP 提供的错误信息的原生界面,以便通知用户。

IdP HTTP API
在 id_assertion_endpoint
响应中,如果 IdP 能够在请求时签发令牌,则可以将令牌返回给浏览器。在此提案中,如果无法签发令牌,IdP 可以返回“错误”响应,其中包含两个新的可选字段:
code
url
// id_assertion_endpoint response
{
"error": {
"code": "access_denied",
"url": "https://idp.example/error?type=access_denied"
}
}
对于代码,IdP 可以从 OAuth 2.0 指定的错误列表 [invalid_request
、unauthorized_client
、access_denied
、server_error
和 temporarily_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;
}
Auto-Selected Flag 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_endpoint
的 POST
请求中添加 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 与我们分享。
照片由 Girl with red hat 在 Unsplash 上发布