Series of tools.

FedCM updates: Login Status API, Error API, and Auto-selected Flag API

The LoginStatus API enables FedCM API without third-party cookies. The Error API and Auto-Selected Flag API bring more capabilities to FedCM API.

Published on

Chrome 120 is shipping the Login Status API for FedCM. The Login Status API (formerly known as IdP Sign-in Status API) allows websites, particularly identity providers, to signal to the browser when their users are logging in and out. This signal is used by FedCM to address a silent timing attack problem, and in doing so, allows FedCM to operate without third-party cookies altogether. This update addresses the last remaining backwards-incompatible changes we previously identified in the original Intent to Ship of FedCM, as part of our scope of work.

While the Login Status API improves the privacy property and usability, it's a backward-incompatible change once shipped. If you have an existing implementation of FedCM, make sure to update it using the following instructions.

Additionally, Chrome is shipping two new Federated Credential Management (FedCM) features:

  • Error API: Notify users when their sign-in attempt fails with a native UI based on the server response from the id assertion endpoint, if any.
  • Auto-Selected Flag API: Notify the identity provider (IdP) and relying party (RP) if a credential was automatically selected in the flow.

Login Status API

Important

The Login Status API is a requirement for FedCM. If you have an existing implementation of FedCM, make sure the Login Status API is implemented, otherwise the FedCM dialog may not show up, even if a user is signed in to the IdP.

The Login Status API is a mechanism where a website, especially an IdP, informs the browser the user's login status on the IdP. With this API, the browser can reduce unnecessary requests to the IdP and mitigate potential timing attacks.

FedCM introduces a credentialed request to the accounts list endpoint. This request doesn't send data that identifies the requestor and doesn't allow passing-through data provided by the RP. Separately, the browser performs an uncredentialed request containing the RP information to the client_metadata_endpoint, so the IdP server can correlate the uncredentialed request with the credentialed request (stochastically) using timestamps or other fingerprinting data. Read more details on GitHub.

Inform the browser about the user's login status

IdPs can signal the user's login status to the browser by sending an HTTP header or by calling a JavaScript API when the user is signed in on the IdP or when the user is signed out from all their IdP accounts. For each IdP (identified by its config URL) the browser keeps a tri-state variable representing the login state with possible values "logged-in", "logged-out", and "unknown. The default state is "unknown".

To signal that the user is signed in, send an Set-Login: logged-in HTTP header in a top-level navigation or a same-origin subresource request:

Set-Login: logged-in

Alternatively, call the JavaScript API navigator.login.setStatus("logged-in") from the IdP origin:

navigator.login.setStatus("logged-in")

These calls record the user's login status as logged-in. When the user's login status is set to logged-in, the RP calling FedCM makes requests to the IdP's accounts list endpoint and displays available accounts to the user in the FedCM dialog.

To signal that the user is signed out from all their accounts, send Set-Login: logged-out HTTP header in a top-level navigation or a same-origin subresource request:

Set-Login: logged-out

Alternatively, call the JavaScript API navigator.login.setStatus("logged-out") from the IdP origin:

navigator.login.setStatus("logged-out")

These calls record the user's login status as "signed-out." When the user's login status is "logged-out," calling the FedCM silently fails without making a request to the IdP's accounts list endpoint.

The "unknown" status is set before the IdP sends a signal using the Login Status API. We introduced this status for a better transition, because a user may have already signed into the IdP when we ship this API. The IdP may not have a chance to signal this to the browser by the time FedCM is first invoked. In this case, we make a request to the IdP's accounts list endpoint and update the status based on the response from the accounts list endpoint:

  • If the endpoint returns a list of active accounts, update the status to "logged-in" and open the FedCM dialog to show those accounts.
  • If the endpoint returns no accounts, update the status to "logged-out" and fail the FedCM call.

What if the user session expires? Let the user sign in through a dynamic login flow!

Even though the IdP keeps informing the user's login status to the browser, it could be out of sync, such as when the session expires. The browser tries to send a credentialed request to the accounts list endpoint when the login status is "logged-in", but the server returns no accounts because the session is no longer available. In such a scenario, the browser can dynamically let the user sign in to the IdP through a popup window.

The FedCM dialog displays a message suggesting a sign in, as shown in the following image.

A FedCM dialog suggesting to sign in to the IdP.
A FedCM dialog suggesting to sign in to the IdP.

When the user clicks the Continue button, the browser opens a dialog for the IdP's login page.

An example dialog.
An example dialog shown after clicking on the sign in to the IdP button.

The website can't control the size of the dialog before it's opened. By default, the size is set to 500 px in width and 600 px in height.

The login page URL is specified with login_url as part of the IdP config file.

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

The dialog is a regular browser window that has first-party cookies. Whatever happens within the dialog is up to the IdP, and no window handles are available to make a cross-origin communication request to the RP page. After the user is signed in, the IdP should:

  • Send the Set-Login: logged-in header or call the navigator.login.setStatus("logged-in") API to inform the browser that the user has been signed in.
  • Call IdentityProvider.close() to close the dialog.
A user signs into an RP after signing in to the IdP using FedCM

This dynamic login experience is intended for when an IdP session has expired without an explicit sign-out, causing the browser's login state to contradict the user's actual state. This isn't triggered for users who haven't signed in to the IdP yet. This new flow is designed to cover the cases where the user's IdP login status on the browser is "logged-in" but the IdP's accounts list endpoint returns no accounts.

Assuming the Login Status API is called promptly, when FedCM is invoked, any of the following scenarios can occur:

  • If the user's login status is set to unknown, the status is updated (either "logged-in" or "logged-out") depending on the IdP's response from the accounts list endpoint. A dynamic login flow won't be triggered.
  • If a user has signed in to the IdP in the browser and then explicitly signed out from the IdP, the dynamic login flow won't be triggered.
  • If a user has signed in to the IdP in the browser, but the session expires without an explicit update to "logged-out," the dynamic login flow is triggered.

The Login Status API does not provide the ability for the RP to display a "Sign-in to the IdP" dialog to users who are not signed in to the IdP. This is a separate feature which may be added in the future.

You can try the Login Status API behavior in our demo.

  1. Tap the Go to the IdP and sign in button.
  2. Sign in with an arbitrary account.
  3. Select Session Expired from Account Status dropdown.
  4. Press the Update personal info button.
  5. Tap the Visit the RP to try FedCM button.

You should be able to observe the login to the IdP through the module behavior.

Error API

When Chrome sends a request to the ID assertion endpoint (for example, when a user clicks the Continue as button on the FedCM UI or auto-reauthentication is triggered), the IdP may not be able to issue a token for legitimate reasons. For example, if the client is unauthorized, the server is temporarily unavailable, and so on. Currently, Chrome fails the request silently in case of such errors and only notifies the RP by rejecting the promise.

With the Error API, Chrome notifies the user by showing a native UI with the error information provided by the IdP.

A FedCM dialog showing the error message after the user's sign-in attempt fails. The string is associated with the error type.
A FedCM dialog showing the error message after the user's sign-in attempt fails. The string is associated with the error type.

IdP HTTP API

In the id_assertion_endpoint, currently the IdP can return a token to the browser if it can be issued upon request. In this proposal, in case a token cannot be issued, the IdP can return an "error" response, which has two new optional fields:

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

For code, the IdP can choose one of the known errors from the OAuth 2.0 specified error list [invalid_request, unauthorized_client, access_denied, server_error and temporarily_unavailable] or use any arbitrary string. If the latter, Chrome renders the error UI with a generic error message and pass the code to the RP.

For url, it identifies a human-readable web page with information about the error to provide additional information about the error to users. This field is useful to users because browsers cannot provide rich error messages in a native UI. For example, links for next steps, customer service contact information and so on. If a user wants to learn more about the error details and how to fix it, they could visit the provided page from the browser UI for more details. The URL must be of the same-site as the IdP configURL.

While we believe that implementing the Error API could bring the best user experience to keep users informed and potentially help users to fix the issue, implementing the Error API is optional. If an IdP doesn't notify the browser about the error type when it occurs, Chrome will show an error UI with a generic message. If the url field is not provided, Chrome doesn't include the More details button.

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 is the default user mediation behavior in the Credential Management API and it triggers automatic re-authentication when possible. However, auto reauthentication may be unavailable due to reasons that only the browser knows; when it's unavailable the user may be prompted to sign in with explicit user mediation, which is a flow with different properties.

  • From an API caller's perspective, when they receive an ID token, they don't have visibility over whether it was an outcome of an auto reauthentication flow. That makes it hard for them to evaluate the API performance and improve UX accordingly.
  • From the IdP's perspective, they are equally unable to tell whether an auto reauthentication occurred or not for performance evaluation. In addition, whether an explicit user mediation was involved could help them support more security related features. For example, some users may prefer a higher security tier which requires explicit user mediation in authentication. If an IdP receives a token request without such mediation, they could handle the request differently. For example, return an error code such that the RP can call the FedCM API again with mediation: required.

Therefore, providing visibility of the auto reauthentication flow would be beneficial to developers.

With the Auto-selected Flag API, Chrome shares whether an explicit user permission was acquired by tapping on the Continue as button with both the IdP and RP, whenever auto reauthentication occurred or an explicit mediation occurred. Sharing only happens after user permission is granted for IdP/RP communication.

IdP sharing

To share the information to the IdP post user permission, Chrome includes is_auto_selected=true in the POST request sent to the id_assertion_endpoint:

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 sharing

The browser can share the information to the RP in isAutoSelected via IdentityCredential:

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

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

Engage and share feedback

If you have feedback or encounter any issues during testing, you can share them at crbug.com.

Photo by Girl with red hat on Unsplash

Published on Improve article

Back

Chrome 120 beta

Next

New in Chrome 119

This site uses cookies to deliver and enhance the quality of its services and to analyze traffic. If you agree, cookies are also used to serve advertising and to personalize the content and advertisements that you see. Learn more about our use of cookies.