FedCM implementation includes several core steps for both Identity Provider (IdP) and Relying Party (RP). Refer to the documentation to learn how to implement FedCM on the RP's side.
IdPs must complete the following steps to implement FedCM:
- Create a well-known file.
- Create a config file.
- Create the following endpoints:
- Account endpoint
- ID assertion endpoint
- [optional] Disconnect endpoint
- [optional] Client metadata endpoint
- Login endpoint
- Inform the browser about user login status.
Create a well-known file
To prevent trackers from abusing the API,
a well-known file must be served from /.well-known/web-identity
of
eTLD+1 of
the IdP.
The well-known file can include the following properties:
Property | Required | Description |
---|---|---|
provider_urls
|
required | Array of IdP configuration file paths. Ignored (but still required) if accounts_endpoint and login_url are specified. |
accounts_endpoint
|
recommended, requires login_url |
URL for the accounts endpoint. This allows for multiple configuration support, as long as each config file uses the same login_url and accounts_endpoint URL.Note: The parameter is supported from Chrome 132. |
login_url
|
recommended, requires accounts_endpoint |
The login page URL for the user to sign in to the IdP. This allows for multiple configuration support, as long as each config file uses the same login_url and accounts_endpoint .Note: the parameter is supported starting in Chrome 132 and later. |
For example, if the IdP endpoints are served under
https://accounts.idp.example/
, they must serve a well-known file at
https://idp.example/.well-known/web-identity
as well as an IdP config
file. Here's an example well-known file content:
{
"provider_urls": ["https://accounts.idp.example/config.json"]
}
IdPs can accommodate multiple config files for an IdP, by specifying
accounts_endpoint
and login_url
in the well-known file.
This feature can be useful in these cases:
- An IdP needs to support multiple different test and production configurations.
- An IdP needs to support different configurations per region (for example,
eu-idp.example
andus-idp.example
).
To support multiple configurations (for example, to differentiate between test
and production environment), IdP must specify accounts_endpoint
and
login_url
:
{
// This property is required, but will be ignored when IdP supports
// multiple configs (when `accounts_endpoint` and `login_url` are
// specified), as long as `accounts_endpoint` and `login_url` in
// that config file match those in the well-known file.
"provider_urls": [ "https://idp.example/fedcm.json" ],
// Specify accounts_endpoint and login_url properties to support
// multiple config files.
// Note: The accounts_endpoint and login_url must be identical
// across all config files. Otherwise,
// the configurations won't be supported.
"accounts_endpoint": "https://idp.example/accounts",
"login_url": "https://idp.example/login"
}
Create an IdP config file and endpoints
The IdP config file provides a list of required endpoints for the browser. IdPs
must host one or multiple config files, and the required endpoints and URLs. All
JSON responses must be served with application/json
content-type.
The config file's URL is determined by the values provided to the
navigator.credentials.get()
call executed on an
RP.
const credential = await navigator.credentials.get({
identity: {
context: 'signup',
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
RP will pass the config file's URL to the FedCM API call to let the user sign in:
// Executed on RP's side:
const credential = await navigator.credentials.get({
identity: {
context: 'signup',
providers: [{
// To allow users to sign in with an IdP using FedCM, RP specifies the IdP's config file URL:
configURL: 'https://accounts.idp.example/fedcm.json',
clientId: '********',
});
const { token } = credential;
The browser will fetch the config file with a GET
request without the Origin
header or the Referer
header. The request doesn't have cookies and doesn't
follow redirects. This effectively prevents the IdP from learning who made the
request and which RP is attempting to connect. For example:
GET /config.json HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Sec-Fetch-Dest: webidentity
IdP must implement a config endpoint that responds with a JSON. The JSON includes the following properties:
Property | Description |
---|---|
accounts_endpoint (required) |
URL for the accounts endpoint. |
accounts.include (optional)
|
Custom account label string, determining which accounts should be returned when this config file is used, for example: "accounts": {"include": "developer"} .
An IdP can implement custom account labelling as follows:
For example, an IdP implements "https://idp.example/developer-config.json" config file with "accounts": {"include": "developer"} specified. The IdP also marks some accounts with "developer" label using the labels parameter in the accounts endpoint. When an RP calls navigator.credentials.get() with "https://idp.example/developer-config.json" config file specified, only accounts with the "developer" label will be returned.Note: Custom Account Labels are supported from Chrome 132. |
client_metadata_endpoint (optional) |
URL for the client metadata endpoint. |
id_assertion_endpoint (required) |
URL for the ID assertion endpoint. |
disconnect (optional) |
URL for the disconnect endpoint. |
login_url (required) |
The login page URL for the user to sign in to the IdP. |
branding (optional) |
Object which contains various branding options. |
branding.background_color (optional) |
Branding option which sets the background color of the "Continue as..." button. Use the relevant CSS syntax, namely
hex-color ,
hsl() ,
rgb() , or
named-color . |
branding.color (optional) |
Branding option which sets the text color of the "Continue as..." button. Use the relevant CSS syntax, namely
hex-color ,
hsl() ,
rgb() , or
named-color . |
branding.icons (optional) |
Array of icon objects. These icons are displayed in the sign-in dialog. The icon object has two parameters:
|
modes |
Object that contains specifications on how FedCM UI will be displayed in different modes:
|
modes.active
|
Object containing properties that allow for customization of FedCM behavior in a specific mode. Both modes.active and modes.passive can contain the following parameter:
Note: Use Other Account feature and active mode are supported from Chrome 132. |
modes.passive
|
Here's an example response body from the IdP:
{
"accounts_endpoint": "/accounts.example",
"client_metadata_endpoint": "/client_metadata.example",
"id_assertion_endpoint": "/assertion.example",
"disconnect_endpoint": "/disconnect.example",
"login_url": "/login",
// When RPs use this config file, only those accounts will be
//returned that include `developer` label in the accounts endpoint.
"accounts": {"include": "developer"},
"modes": {
"active": {
"supports_use_other_account": true,
}
},
"branding": {
"background_color": "green",
"color": "#FFEEAA",
"icons": [{
"url": "https://idp.example/icon.ico",
"size": 25
}]
}
}
Once the browser fetches the config file, it sends subsequent requests to the IdP endpoints:
Use other account
Users can switch to an account that's different from the one they're currently logged in with, if the IdP supports multiple accounts or replacing the existing account.
To enable the user to choose other accounts, the IdP must specify this feature in the config file:
{
"accounts_endpoint" : "/accounts.example",
"modes": {
"active": {
// Allow the user to choose other account (false by default)
"supports_use_other_account": true
}
// "passive" mode can be configured separately
}
}
Accounts endpoint
The IdP's accounts endpoint returns a list of accounts that the user is signed in on the IdP. If the IdP supports multiple accounts, this endpoint will return all signed in accounts.
The browser sends a GET
request with cookies with SameSite=None
, but without
a client_id
parameter, the Origin
header or the Referer
header. This
effectively prevents the IdP from learning which RP the user is trying to sign
in to. For example:
GET /accounts.example HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
Upon receiving the request, the server should:
- Verify that the request contains a
Sec-Fetch-Dest: webidentity
HTTP header. - Match the session cookies with the IDs of the already signed-in accounts.
- Respond with the list of accounts.
The browser expects a JSON response that includes an accounts
property with an
array of account information with following properties:
Property | Description |
---|---|
id (required) |
Unique ID of the user. |
name (required) |
Given and family name of the user. |
email (required) |
Email address of the user. |
given_name (optional) |
Given name of the user. |
picture (optional) |
URL of the user avatar image. |
approved_clients (optional) |
An array of RP client IDs which the user has registered with. |
login_hints (optional) |
An array of all possible filter types that the IdP supports to specify
an account. The RP can invoke navigator.credentials.get()
with the loginHint property to
selectively show the specified account. |
domain_hints (optional) |
An array of all the domains the account is associated with. The RP can
call navigator.credentials.get() with a
domainHint property to filter the
accounts. |
labels (optional)
|
Array of string Custom Account Labels that an account is associated with. An IdP can implement custom account labelling as follows:
For example, an IdP implements https://idp.example/developer-config.json config file with "accounts": {"include": "developer"} specified. The IdP also marks some accounts with "developer" label using the labels parameter in the accounts endpoint. When an RP calls navigator.credentials.get() with https://idp.example/developer-config.json config file specified, only accounts with the "developer" label will be returned.Custom Account Labels are different from Login hint and domain hint in such a way that they are fully maintained by the IdP server, and the RP only specifies the config file to use. Note: Custom Account Labels are supported from Chrome 132. |
Example response body:
{
"accounts": [{
"id": "1234",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
// Ids of those RPs where this account can be used
"approved_clients": ["123", "456", "789"],
// This account has 'login_hints`. When an RP calls `navigator.credentials.get()`
// with a `loginHint` value specified, for example, `exampleHint`, only those
// accounts will be shown to the user whose 'login_hints' array contains the `exampleHint`.
"login_hints": ["demo1", "exampleHint"],
// This account is labelled. IdP can implement a specific config file for a
// label, for example, `https://idp.example/developer-config.json`. Like that
// RPs can filter out accounts by calling `navigator.credentials.get()` with
// `https://idp.example/developer-config.json` config file.
"labels": ["hr", "developer"]
}, {
"id": "5678",
"given_name": "Johnny",
"name": "Johnny",
"email": "johnny@idp.example",
"picture": "https://idp.example/profile/456",
"approved_clients": ["abc", "def", "ghi"],
"login_hints": ["demo2"],
"domain_hints": ["@domain.example"]
}]
}
If the user is not signed in, respond with HTTP 401
(Unauthorized).
The returned accounts list is consumed by the browser and won't be available to the RP.
ID assertion endpoint
The IdP's ID assertion endpoint returns an assertion for their signed-in user.
When the user signs in to an RP website using navigator.credentials.get()
call, the browser sends
a POST
request with cookies with SameSite=None
and a content-type of
application/x-www-form-urlencoded
to this endpoint with the following
information:
Property | Description |
---|---|
client_id (required) |
The RP's client identifier. |
account_id (required) |
The unique ID of the signing in user. |
disclosure_text_shown |
Results in a string of "true" or "false" (rather than a boolean). The result is "false" in these cases:
|
is_auto_selected |
If auto-reauthentication is performed on the RP, is_auto_selected indicates "true" . Otherwise "false" . This is helpful to 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 . |
fields (optional)
|
Array of strings that specifies the user information ("name", " email", "picture") that RP needs IdP to share with them. The browser will send fields , disclosure_text_shown , and disclosure_shown_for listing the specified fields in the POST request, as in the following example.Note: The Fields parameter is supported from Chrome 132. |
params (optional)
|
Any valid JSON object that allows to specify additional custom key-value parameters, for example:
params value will be serialized to JSON and then percent-encoded.Note: Parameters API is supported by Chrome 132 and later. |
Example HTTP header:
POST /assertion.example HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Content-Type: application/x-www-form-urlencoded
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
// disclosure_text_shown is set to 'false', as the 'name' field value is missing in 'fields' array
// params value is serialized to JSON and then percent-encoded.
account_id=123&client_id=client1234&disclosure_text_shown=false&is_auto_selected=true¶ms=%22%7B%5C%22nonce%5C%22%3A%5C%22nonce-value%5C%22%7D%22.%0D%0A4&disclosure_text_shown=true&fields=email,picture&disclosure_shown_for=email,picture
Upon receiving the request, the server should:
- Respond to the request with CORS (Cross-Origin Resource Sharing).
- Verify that the request contains a
Sec-Fetch-Dest: webidentity
HTTP header. - Match the
Origin
header against the RP origin determined by theclient_id
. Reject if they don't match. - Match
account_id
against the ID of the already signed-in account. Reject if they don't match. - Respond with a token. If the request is rejected, respond with an error response.
IdP can decide how they issue the token. In general, it's signed with information such as the account ID, client ID, issuer origin, and nonce, so that the RP can verify the token is genuine.
The browser expects a JSON response that includes the following property:
Property | Description |
---|---|
token |
A token is a string that contains claims about the authentication. |
continue_on |
Redirect URL that enables a multi-step sign-in flow. |
The returned token is passed to the RP by the browser, so that the RP can validate the authentication.
{
// IdP can respond with a token to authenticate the user
"token": "***********"
}
Continue on feature
The IdP can provide a redirect URL in the ID assertion endpoint response to enable a multi-step sign-in flow. This is useful when the IdP needs to request additional information or permissions, for example:
- Permission to access the user's server-side resources.
- Verification that contact information is up-to-date.
- Parental controls.
The ID assertion endpoint can return a continue_on
property which includes an
absolute or relative path to the ID assertion endpoint.
{
// In the id_assertion_endpoint, instead of returning a typical
// "token" response, the IdP decides that it needs the user to
// continue on a popup window:
"continue_on": "https://idp.example/continue_on_url"
}
If the response contains the continue_on
parameter, a new popup window is
opened and navigates the user to the specified path. After the user interaction
with the continue_on
page, the IdP should call IdentityProvider.resolve()
with the token passed as an argument so that the promise from the original
navigator.credentials.get()
call can be resolved:
document.getElementById('example-button').addEventListener('click', async () => {
let accessToken = await fetch('/generate_access_token.cgi');
// Closes the window and resolves the promise (that is still hanging
// in the relying party's renderer) with the value that is passed.
IdentityProvider.resolve(accessToken);
});
The browser will then automatically close the popup and return the token to the
API caller. A one-time IdentityProvider.resolve()
call is the only way for the
parent window (RP) and the popup window (IdP) to communicate.
If the user rejects the request, IdP can close the window by calling
IdentityProvider.close()
.
IdentityProvider.close();
The Continuation API requires explicit user interaction (clicks) to function. Here's how Continuation API works with different mediation modes:
- In passive mode:
mediation: 'optional'
(default): the Continuation API will only work with a user gesture, such as clicking on a button on the page or on the FedCM UI. When auto re-authentication is triggered without a user gesture, no popup window is opened, and the promise is rejected.mediation: 'required'
: Always asks the user to interact, so the Continuation API always works.
- In active mode:
- User activation is always required. The Continuation API is compatible.
If for some reason the user has changed their account in the popup (for example, the IdP offers a "use other account" function, or in delegation cases), the resolve call takes an optional second argument allowing something like:
IdentityProvider.resolve(token, {accountId: '1234');
Return an error response
The id_assertion_endpoint
can also return an "error"
response, which has two optional fields:
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
andtemporarily_unavailable
) or use any arbitrary string. If the latter, Chrome renders the error UI with a generic error message and passes the code to the RP.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 built-in UI. For example: links for next steps, or customer service contact information. 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 IdPconfigURL
.
// id_assertion_endpoint response
{
"error" : {
"code": "access_denied",
"url" : "https://idp.example/error?type=access_denied"
}
}
Custom Account Labels
With Custom Account Labels, the
IdP can annotate user accounts with labels, and the RP can choose to only fetch
accounts with specific labels by specifying the configURL
for that specific
label. This can be useful when an RP needs to filter out accounts by specific
criteria, for example, to only display role-specific accounts such as
"developer"
or "hr"
.
Similar filtering is possible using the Domain Hint and the
Login Hint features, by specifying them in the
navigator.credentials.get()
call. However, Custom Account Labels can filter
users by specifying the config file, which is especially useful when multiple
configURLs are used. Custom Account Labels are also different
in that they are provided from the IdP server, as opposed to from the RP, like
login or domain hints.
Consider an IdP that wants to differentiate between "developer"
and "hr"
accounts. To achieve this, the IdP needs to support two configURLs for
"developer"
and "hr"
respectively:
- The developer config file
https://idp.example/developer/fedcm.json
has a"developer"
label, and the enterprise config filehttps://idp.example/hr/fedcm.json
has an"hr"
label as follows:
// The developer config file at `https://idp.example/developer/fedcm.json`
{
"accounts_endpoint": "https://idp.example/accounts",
"client_metadata_endpoint": "/client_metadata",
"login_url": "https://idp.example/login",
"id_assertion_endpoint": "/assertion",
"accounts": {
// Account label
"include": "developer"
}
}
// The hr config file at `https://idp.example/hr/fedcm.json`
{
"accounts_endpoint": "https://idp.example/accounts",
"client_metadata_endpoint": "/client_metadata",
"login_url": "https://idp.example/login",
"id_assertion_endpoint": "/assertion",
"accounts": {
// Account label
"include": "hr"
}
}
- With such a setup, the well-known file should include
accounts_endpoint
andlogin_url
to allow multiple configURLs:
{
"provider_urls": [ "https://idp.example/fedcm.json" ],
"accounts_endpoint": "https://idp.example/accounts",
"login_url": "https://idp.example/login"
}
- The common IdP accounts endpoint (in this example
https://idp.example/accounts
) returns a list of accounts that includes alabels
property with assigned labels in an array for each account:
{
"accounts": [{
"id": "123",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"labels": ["developer"]
}], [{
"id": "4567",
"given_name": "Jane",
"name": "Jane Doe",
"email": "jane_doe@idp.example",
"picture": "https://idp.example/profile/4567",
"labels": ["hr"]
}]
}
When an RP wants to allow "hr"
users to sign in, they can specify the
configURL https://idp.example/hr/fedcm.json
in the
navigator.credentials.get()
call:
let { token } = await navigator.credentials.get({
identity: {
providers: [{
clientId: '1234',
nonce: '234234',
configURL: 'https://idp.example/hr/fedcm.json',
},
}
});
As a result, only the account ID of 4567
is available for the user to sign in.
The account ID of 123
is silently hidden by the browser so that the user won't
be provided with an account that's not supported by the IdP on this site.
- Labels are strings. If the
labels
array orinclude
field contains something that is not a string, it is ignored. - If no labels are specified in the
configURL
, all accounts will be displayed in the FedCM account chooser. - If no labels are specified for an account, it will only be displayed in the
account chooser if the
configURL
also does not specify a label. - If no account matches the requested label in passive mode (similar to the Domain Hint feature), the FedCM dialog shows a login prompt, which allows the user to sign in to an IdP account. For the active mode, the login popup window is directly opened.
Disconnect endpoint
By invoking IdentityCredential.disconnect()
, the browser sends a cross-origin
POST
request with cookies with SameSite=None
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.example 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 server should:
- Respond to the request with CORS (Cross-Origin Resource Sharing).
- Verify that the request contains a
Sec-Fetch-Dest: webidentity
HTTP header. - Match the
Origin
header against the RP origin determined by theclient_id
. Reject if they don't match. - Match
account_hint
against the IDs of the already signed-in accounts. - Disconnect the user account from the RP.
- Respond to the browser with the identified user account information in a JSON format.
An example response JSON payload looks like this:
{
"account_id": "account456"
}
Instead, if the IdP wishes the browser to disconnect all accounts associated
with the RP, pass a string that does not match any account ID, for example
"*"
.
Client metadata endpoint
The IdP's client metadata endpoint returns the relying party's metadata such as the RP's privacy policy, terms of service, and logo icons. RPs should provide links to their privacy policy and terms of service to the IdP in advance. These links are displayed in the sign-in dialog when the user hasn't registered on the RP with the IdP yet.
The browser sends a GET
request using the client_id
navigator.credentials.get
without cookies. For example:
GET /client_metadata.example?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity
Upon receiving the request, the server should:
- Determine the RP for the
client_id
. - Respond with the client metadata.
The properties for the client metadata endpoint include:
Property | Description |
---|---|
privacy_policy_url (optional) |
RP privacy policy URL. |
terms_of_service_url (optional) |
RP terms of service URL. |
icons (optional) |
Array of objects, such as [{ "url": "https://rp.example/rp-icon.ico", "size": 40}] |
The browser expects a JSON response from the endpoint:
{
"privacy_policy_url": "https://rp.example/privacy_policy.html",
"terms_of_service_url": "https://rp.example/terms_of_service.html",
"icons": [{
"url": "https://rp.example/rp-icon.ico",
"size": 40
}]
}
The returned client metadata is consumed by the browser and won't be available to the RP.
Login URL
This endpoint is used to let the user sign in to the IdP.
With the Login Status API, the IdP must inform the user's
login status to the browser. However, the status could be out of sync, such as
when the session expires. In such a scenario, the
browser can dynamically let the user sign in to the IdP through the login page
URL specified with the idp config file's login_url
.
The FedCM dialog displays a message suggesting a sign in, as shown in the following image.
When the user clicks the Continue button, the browser opens a popup window for the IdP's login page.
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 thenavigator.login.setStatus("logged-in")
API to inform the browser that the user has been signed in. - Call
IdentityProvider.close()
to close the dialog.
Inform the browser about the user's login status
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.
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
unknown
(default)
Login state | Description |
---|---|
logged-in |
When the user's login status is set to logged-in , the RP calling FedCM makes requests to the IdP's accounts endpoint and displays available accounts to the user in the FedCM dialog. |
logged-out |
When the user's login status is logged-out , calling the FedCM silently fails without making a request to the IdP's accounts endpoint. |
unknown (default) |
The unknown status is set before the IdP sends a signal using the Login Status API. When the status is unknown , the browser makes a request to the IdP's accounts endpoint and updates the status based on the response from the accounts endpoint. |
To signal that the user is signed in, send an Set-Login: logged-in
HTTP header
in a top-level navigation or a same-site subresource request at the IdP origin:
Set-Login: logged-in
Alternatively, call the JavaScript method
navigator.login.setStatus('logged-in')
from the IdP origin in a top-level
navigation:
navigator.login.setStatus('logged-in')
The user's login status will be set as logged-in
.
To signal that the user is signed out from all their accounts, send a
Set-Login: logged-out
HTTP header in a top-level navigation or a same-site
subresource request at the IdP origin:
Set-Login: logged-out
Alternatively, call the JavaScript API navigator.login.setStatus('logged-out')
from the IdP origin in a top-level navigation:
navigator.login.setStatus('logged-out')
The user's login status will be set as logged-out
.
The unknown
status is set before the IdP sends a signal using the Login Status
API. The browser makes a request to the IdP's accounts endpoint and update the
status based on the response from the accounts 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.
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 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.