docs.rodeo

MDN Web Docs mirror

Identity provider integration with FedCM

{{DefaultAPISidebar("FedCM API")}} 

This article details all the steps an identity provider (IdP) needs to take to integrate with the Federated Credential Management (FedCM) API.

IdP integration steps

To integrate with FedCM, an IdP needs to do the following:

  1. Provide a well-known file to identify the IdP.
  2. Provide a config file and endpoints for accounts list and assertion issuance (and optionally, client metadata).
  3. Update its login status using the Login Status API.

Provide a well-known file

There is a potential privacy issue whereby an IdP is able to discern whether a user visited an RP without explicit consent. This has tracking implications, so an IdP is required to provide a well-known file to verify its identity and mitigate this issue.

The well-known file is requested via an uncredentialed GET request, which doesn’t follow redirects. This effectively prevents the IdP from learning who made the request and which RP is attempting to connect.

The well-known file must be served from the eTLD+1 of the IdP at /.well-known/web-identity. 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. The well-known file’s content should have the following JSON structure:

{
  "provider_urls": ["https://accounts.idp.example/config.json"]
}

The provider_urls member should contain an array of URLs pointing to valid IdP config files that can be used by RPs to interact with the IdP. The array length is currently limited to one.

The Sec-Fetch-Dest HTTP header

All requests sent from the browser via FedCM include a ``{{httpheader(“Sec-Fetch-Dest”)}} : webidentity header. All IdP endpoints that receive credentialed requests (i.e. accounts_endpoint and id_assertion_endpoint) must confirm this header is included to protect against {{glossary("CSRF")}}  attacks.

Provide a config file and endpoints

The IdP config file provides a list of the endpoints the browser needs to process the identity federation flow and manage the sign-ins. The endpoints need to be same-origin with the config.

The browser makes an uncredentialed request for the config file via the GET method, which doesn’t follow redirects. This effectively prevents the IdP from learning who made the request and which RP is attempting to connect.

The config file (hosted at https://accounts.idp.example/config.json in our example) should have the following JSON structure:

{
  "accounts_endpoint": "/accounts.php",
  "client_metadata_endpoint": "/client_metadata.php",
  "id_assertion_endpoint": "/assertion.php",
  "login_url": "/login",
  "branding": {
    "background_color": "green",
    "color": "0xFFEEAA",
    "icons": [
      {
        "url": "https://idp.example/icon.ico",
        "size": 25
      }
    ]
  }
}

The properties are as follows:

The following table summarizes the different requests made by the FedCM API:

Endpoint/resource Method Credentialed (with cookies) Includes {{httpheader("Origin")}} 
well-known/config.json GET No No
accounts_endpoint GET Yes No
client_metadata_endpoint GET No Yes
id_assertion_endpoint POST Yes Yes

[!NOTE] For a description of the FedCM flow in which these endpoints are accessed, see FedCM sign-in flow.

[!NOTE] None of the requests made by the FedCM API to the endpoints detailed here allow for following redirects, for privacy purposes.

The accounts list endpoint

The browser sends credentialed requests (i.e. with a cookie that identifies the user that is signed in) to this endpoint via the GET method. The request has no client_id parameter, {{httpheader("Origin")}}  header, or {{httpheader("Referer")}}  header. This effectively prevents the IdP from learning which RP the user is trying to sign in to. The list of accounts returned is RP-agnostic.

For example:

GET /accounts.php HTTP/1.1
Host: idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity

The response to a successful request returns a list of all the IdP accounts that the user is currently signed in with (not specific to any particular RP), with a JSON structure that matches the following:

{
  "accounts": [
    {
      "id": "john_doe",
      "given_name": "John",
      "name": "John Doe",
      "email": "john_doe@idp.example",
      "picture": "https://idp.example/profile/123",
      "approved_clients": ["123", "456", "789"],
      "login_hints": ["john_doe", "john_doe@idp.example"]
    },
    {
      "id": "johnny",
      "given_name": "Johnny",
      "name": "Johnny",
      "email": "johnny@idp.example",
      "picture": "https://idp.example/profile/456",
      "approved_clients": ["abc", "def", "ghi"],
      "login_hints": ["johnny", "johnny@idp.example"]
    }
  ]
}

This includes the following information:

[!NOTE] If the user is not signed in to any IdP accounts, the endpoint should respond with HTTP 401 (Unauthorized).

The client metadata endpoint

The browser sends uncredentialed requests to this endpoint via the GET method, with the clientId passed into the get() call as a parameter.

For example:

GET /client_metadata.php?client_id=1234 HTTP/1.1
Host: idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity

The response to a successful request includes URLs pointing to the RP’s metadata and terms of service pages, to be used in the browser-supplied FedCM UI. This should follow the JSON structure seen below:

{
  "privacy_policy_url": "https://rp.example/privacy_policy.html",
  "terms_of_service_url": "https://rp.example/terms_of_service.html"
}

The ID assertion endpoint

The browser sends credentialed requests to this endpoint via the POST method, with a content type of application/x-www-form-urlencoded. The request also includes a payload including details about the attempted sign-in and the account to be validated.

It should look something like this:

POST /assertion.php 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=Ct60bD&disclosure_text_shown=true&is_auto_selected=true

A request to this endpoint is sent as a result of the user choosing an account to sign in with from the relevant browser UI. When sent valid user credentials, this endpoint should respond with a validation token that the RP can use to validate the user on its own server, according to the usage instructions outlined by the IdP they are using for identity federation. Once the RP validates the user, they can sign them in, sign them up to their service, etc.

{
  "token": "***********"
}

The request payload contains the following params:

[!NOTE] If the {{domxref("CredentialsContainer.get", "get()")}}  call succeeds, the is_auto_selected value is also communicated to the RP via the {{domxref("IdentityCredential.isAutoSelected")}}  property.

ID assertion error responses

If the IdP cannot issue a token — for example if the client is unauthorized — the ID assertion endpoint will respond with an error response containing information about the nature of the error. For example:

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

The error response fields are as follows:

This information can be used in a couple of different ways:

Update login status using the Login Status API

The Login Status API allows an IdP to inform a browser of its login (sign-in) status in that particular browser — by this, we mean “whether any users are logged into the IdP on the current browser or not”. The browser stores this state for each IdP; the FedCM API then uses it to reduce the number of requests it makes to the IdP (because it does not need to waste time requesting accounts when there are no users logged in to the IdP). It also mitigates potential timing attacks.

For each known IdP (identified by its config URL) the browser keeps a tri-state variable representing the login state with three possible values:

Setting login status

The IdP should update its login status when a user signs into or out of the IdP. This can be done in two different ways:

How login status affects federated sign-in flow

When an RP attempts federated sign-in, the login status is checked:

What if the browser and the IdP login status become out of sync?

Despite the Login Status API informing the browser of the IdP’s login status, it is possible for the browser and IdP to become out of sync. For example, the IdP sessions might expire, meaning that all user accounts end up signed out but the login status is still set to "logged-in" (the application was not able to set the login status to "logged-out"). In such a case, when federated sign-in is attempted, a request will be made to the IdP’s accounts list endpoint but no available accounts will be returned because the session is no longer available.

When this occurs, the browser can dynamically let a user sign into the IdP by opening the IdP’s sign-in page in a dialog (the sign-in URL is found in the IdP’s config file login_url ). The exact nature of this flow is up to the browser; for example, Chrome handles it like this.

Once the user is signed in to the IdP, the IdP should:

See also

In this article

View on MDN