Chrome nettleser, Nyheter

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

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 IdentityProvider.logout() 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

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: ,
}
});
} 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:
}
});

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

This post is also available in: English

author-avatar

About Aksel Lian

En selvstendig full stack webutvikler med en bred variasjon av kunnskaper herunder SEO, CMS, Webfotografi, Webutvikling inkl. kodespråk..