FedCM updates: Disconnect API and two updates

From Chrome 122, the Disconnect API for Federated Credential Management API (FedCM) is available. The Disconnect API allows relying parties to disconnect their users from the identity provider's account without relying on third-party cookies. Also, there are a couple of updates to FedCM's same-site handling.

Disconnect API

When a user creates an account on a relying party (RP—the site using the identity provider for authentication) through identity federation, the identity provider (IdP—the service which provides authentication and account information to other parties) typically records the connection on its server. The stored connection allows the IdP to keep track of RPs that the user has signed into and optimize their experience. For example, to have a better experience when the user later returns to the RP, the user account with the IdP is treated as a returning account, which allows features such as auto reauthentication and personalized buttons showing the account used.

Sometimes, IdPs offer an API to disconnect the account from an RP. However, a disconnect flow is authenticated and requires the IdP cookies. In a world without third-party cookies, when the user visits the RP, there is no browser API for the RP to disconnect from the IdP. Because there may be multiple IdP accounts from the same IdP linked to a given RP, the disconnect flow requires knowing which account is being disconnected.

The Disconnect API allows the user to disconnect the IdP account from the RP on the browser as well as on the IdP server by signaling it to the specified endpoint. The user needs to have gone through identity federation using the Federated Credential Management API (FedCM). Once the user is disconnected, they are treated as a new user the next time they try to sign in to the RP using the IdP.

Disconnect the IdP from the RP

If a user has previously signed into the RP using the IdP through FedCM, the relationship is memorized by the browser locally as the list of connected accounts. The RP may initiate a disconnection by invoking the IdentityCredential.disconnect() function. This function can be called from a top-level RP frame. The RP needs to pass a configURL, the clientId it uses under the IdP, and an accountHint for the IdP to be disconnected. An account hint can be an arbitrary string as long as the disconnect endpoint can identify the account, for example an email address or user ID which does not necessarily match the account ID that the account list endpoint has provided:

// 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() returns a Promise. This promise may throw an exception for the following reasons:

  • The user hasn't signed in to the RP using the IdP through FedCM.
  • The API is invoked from within an iframe without FedCM permissions policy.
  • The configURL is invalid or missing the disconnect endpoint.
  • Content Security Policy (CSP) check fails.
  • There is a pending disconnect request.
  • The user has disabled FedCM in the browser settings.

When the IdP's disconnect endpoint returns a response, the RP and the IdP are disconnected on the browser and the promise is resolved. The disconnecting user accounts are specified in the response from the disconnect endpoint.

Set up IdP config file

In order to support the Disconnect API, the IdP must support a disconnect endpoint and provide the disconnect_endpoint property and its path in its IdP config file.

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

Disconnect the account on the disconnect endpoint

By invoking IdentityCredential.disconnect(), the browser sends a cross-origin POST request with cookies and a content-type of application/x-www-form-urlencoded to this disconnect endpoint with the following information:

Property Description
account_hint A hint for the IdP account.
client_id The RP's client identifier.
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

Upon receiving the request, the IdP server should:

  1. Respond to the request with CORS (Cross-Origin Resource Sharing).
  2. Verify that the request contains a Sec-Fetch-Dest: webidentity HTTP header.
  3. Match the Origin header against the RP origin determine by the client_id. Reject if they don't match.
  4. Find the account that matches the account_hint.
  5. Disconnect the user account from the list of RP's connected accounts.
  6. Respond to the browser with the identified user's account_id in a JSON format.

An example response JSON payload looks like this:

{
  "account_id": "account456"
}

If the IdP wishes the browser to instead disconnect all accounts associated with the RP, pass a string that does not match any account ID, for example "*".

Checking /.well-known/web-identity is now skipped when the RP and IdP are same-site

When developing a FedCM system, testing or staging RP server domains may be the subdomains of the production IdP server. For example, the production IdP server is at idp.example and both the staging RP server and the staging IdP server are at staging.idp.example. However, since the well-known file must be placed at the root of the IdP server's eTLD+1, it has to be at idp.example/.well-known/web-identity and it's the production server. Since it's not necessarily possible for developers to place files in the production environment while under development, this prevents them from testing FedCM.

Starting from Chrome 122, if the RP domain and IdP domain are the same, Chrome skips checking the well-known file. This way, developers will be able to test in such a scenario.

Subresources can now set same-site login status

Previously, Chrome has only allowed setting the login status (for example, using the Set-Login: logged-in header) when the request is the same-origin with all ancestors. This prevented logins through the same-site fetch() requests setting login status.

For example, think about a website that lets users enter their username and password on idp.example, but the credentials are posted to login.idp.example with fetch(). Recording the login status to the browser using the Login Status API wasn't possible because the two domains are cross-origin and same-site.

With this change, we have relaxed the requirement for the Login Status API to be the same-site with all ancestors and makes the above example possible to set login.idp.example's login status using an HTTP header (Set-Login: logged-in).

Summary

By using the Disconnect API, FedCM can now disconnect the RP from the IdP without relying on third-party cookies. To do so, call IdentityCredential.disconnect() on the RP. With this function, the browser sends a request to IdP's disconnect endpoint so that the IdP can terminate the connection on the server, and then on the browser.

We've announced that /.well-known/web-identity check is skipped when the RP and the IdP are the same-site, for testing purposes. Also, setting a login status through an HTTP response header from the same-site IdP subresource is now possible.