Learn how to use FedCM for privacy-preserving identity federation.
FedCM (Federated Credential Management) is a privacy-preserving approach to federated identity services (such as "Sign in with...") where users can log into sites without sharing their personal information with the identity service or the site.
To learn more about FedCM use cases, user flows, and API roadmap check out the introduction to FedCM API.
FedCM development environment
You need a secure context (HTTPS or localhost) both on the IdP and RP in Chrome to use the FedCM.
Debug code on Chrome on Android
Set up and run a server locally to debug your FedCM code. You can access this server in Chrome on an Android device connected using a USB cable with port forwarding.
You can use DevTools on desktop to debug Chrome on Android by following the instructions at Remote debug Android devices.
Block third-party cookies on Chrome

You can test how FedCM works without third-party cookies on Chrome before it's actually enforced.
To block third-party cookies, use Incognito
mode, or choose "Block
third-party cookies" in your desktop settings at chrome://settings/cookies
or on
mobile by navigating to Settings > Site settings > Cookies.
Using the FedCM API
You integrate with FedCM by creating a well-known file, config file and endpoints for accounts list, assertion issuance and optionally client metadata.
From there, FedCM exposes JavaScript APIs that RPs can use to sign in with the IdP.
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.
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"]
}
The JSON file must contain the provider_urls
property with an array of IdP
config file URLs that can be specified as a path part of
configURL
in navigator.credentials.get
by RPs. The number of
URL strings in the array is limited to one, but this may change with your
feedback in the future.
Create an IdP config file and endpoints
The IdP config file provides a list of required endpoints for the browser. IdPs
will host this config file and the required endpoints. All JSON response 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: '******',
loginHint: 'demo1@example.com'
}]
}
});
const { token } = credential;
Specify a full URL of the IdP config file location as a configURL
. When
navigator.credentials.get()
is called on the RP, the browser
fetches 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
The browser expects a JSON response from the IdP which includes the following properties:
Property | Description |
---|---|
accounts_endpoint (required) |
URL for the accounts list endpoint. |
client_metadata_endpoint (optional) |
URL for the client metadata endpoint. |
id_assertion_endpoint (required) |
URL for the ID assertion endpoint. |
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) |
Branding option which sets the icon object, displayed in the sign-in dialog. The icon object is an array with two parameters:
|
RP could modify the string in the FedCM dialog UI via identity.context
value for navigator.credentials.get()
to accommodate predefined authentication contexts. Optional property can be one of "signin"
(default), "signup"
, "use"
or "continue"
.
Here's an example response body from the IdP:
{
"accounts_endpoint": "/accounts.php",
"client_metadata_endpoint": "/client_metadata.php",
"id_assertion_endpoint": "/assertion.php",
"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:
Accounts list endpoint
The IdP's accounts list endpoint returns a list of accounts that the user is currently 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, 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.php HTTP/1.1
Host: accounts.idp.example
Accept: application/json
Cookie: 0x23223
Sec-Fetch-Dest: webidentity
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. |
Example response body:
{
"accounts": [{
"id": "1234",
"given_name": "John",
"name": "John Doe",
"email": "john_doe@idp.example",
"picture": "https://idp.example/profile/123",
"approved_clients": ["123", "456", "789"],
"login_hints": ["demo1", "demo1@example.com"],
}, {
"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", "demo2@example.com"],
}]
}
If the user is not signed in, respond with HTTP 401 (Unauthorized).
The returned accounts list is consumed by the browser and will not be available to the RP.
By passing login_hints in the accounts list, the RP can invoke navigator.credentials.get()
with the loginHint
property to selectively show the specified account.
Client metadata endpoint
The IdP's client metadata endpoint returns the relying party's metadata such as the RP's privacy policy and terms of service. 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.php?client_id=1234 HTTP/1.1
Host: accounts.idp.example
Origin: https://rp.example/
Accept: application/json
Sec-Fetch-Dest: webidentity
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. |
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",
}
The returned client metadata is consumed by the browser and will not 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 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. |
nonce (optional) |
The request nonce, provided by the RP. |
disclosure_text_shown |
Results in a string of "true" or "false" (rather than a boolean). The result is "false" if the disclosure text was not shown. This happens when the RP's client ID was included in the approved_clients property list of the response from the accounts list endpoint or if the browser has observed a sign-up moment in the past in the absence of approved_clients . |
Example HTTP header:
POST /assertion.php HTTP/1.1
Host: accounts.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
On the server, the IdP should confirm that:
- The claimed account ID matches the ID for the account that is already signed in.
- The
Origin
header matches the origin the RP, registered in advance for the given client ID.
The browser expects a JSON response that includes the following property:
Property | Description |
---|---|
token (required) |
A token is a string that contains claims about the authentication. |
{
"token": "***********"
}
The returned token is passed to the RP by the browser, so that the RP can validate the authentication.
Sign in to the relying party with the identity provider
Once the IdP's configuration and endpoints are available, RPs can call
navigator.credentials.get()
to request allowing users to sign in to the RP
with the IdP.
Before calling the API, you need to confirm that [FedCM is available on the user's browser]. To check if FedCM is available, wrap this code around your FedCM implementation:
if ('IdentityCredential' in window) {
// If the feature is available, take action
}
To request allowing users to sign in to the IdP from the RP, do the following, for example:
const credential = await navigator.credentials.get({
identity: {
providers: [{
configURL: 'https://accounts.idp.example/config.json',
clientId: '********',
nonce: '******'
}]
}
});
const { token } = credential;
The providers
property takes an array of IdentityProvider
objects that have
the following properties:
Property | Description |
---|---|
configURL (required) |
A full path of the IdP config file. |
clientId (required) |
The RP's client identifier, issued by the IdP. |
nonce (optional) |
A random string to ensure the response is issued for this specific request. Prevents replay attacks. |
The browser handles sign-up and sign-in use cases differently depending on the
existence of approved_clients
in the response from the accounts list
endpoint. The browser will not display a disclosure
text "To continue with ...." if the user has already signed up to the RP.
The sign-up state is determined based on whether the following conditions are fulfilled or not:
- If
approved_clients
includes the RP'sclientId
. - If the browser remembers that the user has already signed up to the RP.
When the RP calls navigator.credentials.get()
, the following activities take
place:
- The browser sends requests and fetches several documents:
- The well-known file and an IdP config file which declare endpoints.
- An accounts list.
- Optional: URLs for the RP's privacy policy and terms of service, retrieved from the client metadata endpoint.
- The browser displays the list of accounts that the user can use to sign-in, as well as the terms of service and privacy policy if available.
- Once the user chooses an account to sign in with, a request to the ID assertion endpoint is sent to the IdP to retrieve a token.
- The RP can validate the token to authenticate the user.
Once the token is validated by the RP server, the RP may register the user or let them sign-in and start a new session.
Auto-reauthenticate users after the initial consent
FedCM auto-reauthentication ("auto-reauthn" in short) can let users reauthenticate automatically, when they come back after their initial authentication using FedCM. "The initial authentication" here means the user creates an account or signs into the RP's website by tapping on the "Continue as..." button on FedCM's sign-in dialog for the first time on the same browser instance.
While the explicit user experience makes sense before the user has created the federated account to prevent tracking (which is one of the main goals of FedCM), it is unnecessarily cumbersome after the user has gone through it once: after the user grants permission to allow communication between the RP and the IdP, there's no privacy or security benefit for enforcing another explicit user confirmation for something that they have already previously acknowledged.
With auto-reauthentication, the browser changes its behavior depending on the option you specify for the mediation
when calling navigator.credentials.get()
.
const cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: "https://idp.example/fedcm.json",
clientId: "1234",
}],
},
mediation: 'optional', // this is the default
});
The mediation
is a property in the Credential Management
API,
it behaves in the same
way as it
does for
PasswordCredential
and
FederatedCredential
and it's partially supported by
PublicKeyCredential
as well. The property accepts the following four values:
'optional'
(default): Auto-reauthn if possible, requires a mediation if not. We recommend choosing this option on the sign-in page.'required'
: Always requires a mediation to proceed, for example, clicking the "Continue" button on the UI. Choose this option if your users are expected to grant permission explicitly every time they need to be authenticated.'silent'
: Auto-reauthn if possible, silently fail without requiring a mediation if not. We recommend choosing this option on the pages other than the dedicated sign-in page but where you want to keep users signed in—for example, an item page on a shipping website or an article page on a news website.'conditional'
: Used for WebAuthn and not available for FedCM at the moment.
With this call, auto-reauthn happens under the following conditions:
- FedCM is available to use. For example, the user has not disabled FedCM either globally or for the RP in the settings.
- The user used only one account with FedCM API to sign into the website on this browser.
- The user is signed into the IdP with that account.
- The auto-reauthn didn't happen within the last 10 minutes.
- The RP hasn't called
navigator.credentials.preventSilentAccess()
after the previous sign in.
When the above conditions are met, an attempt to automatically reauthenticate
the user starts as soon as the FedCM navigator.credentials.get()
is invoked.
Enforce mediation with preventSilentAccess()
Auto-reauthenticating users immediately after they sign out would not make for a
very good user experience. That's why FedCM has a 10-minute quiet period after
an auto-reauthn to prevent this behavior. This means that auto-reauthn happens
at most once in every 10-minutes unless the user signs back in within
10-minutes. The RP should call navigator.credentials.preventSilentAccess()
to
explicitly request the browser to disable auto-reauthn when a user signs out of
the RP explicitly, for example, by clicking a sign-out button.
function signout() {
navigator.credentials.preventSilentAccess();
location.href = '/signout';
}
Users can opt-out of auto-reauthn in settings
Users can opt-out from auto-reauth from the settings menu:
- On desktop Chrome, go to
chrome://password-manager/settings
> Sign in automatically. - On Android Chrome, open Settings > Password Manager > Tap on a cog at the top right corner > Auto sign-in.
By disabling the toggle, the user can opt-out from auto-reauthn behavior all together. This setting is stored and synchronized across devices, if the user is signed into a Google account on the Chrome instance and synchronization is enabled.
Call FedCM from within a cross-origin iframe
FedCM can be invoked from within a cross-origin iframe using an identity-credentials-get
permissions policy, if the parent frame allows it. To do so, append the allow="identity-credentials-get"
attribute to the iframe tag as follows:
<iframe src="https://fedcm-cross-origin-iframe.glitch.me" allow="identity-credentials-get"></iframe>
You can see it in action in an example.
Optionally, if the parent frame wants to restrict the origins to call FedCM,
send a Permissions-Policy
header with a list of allowed origins.
Permissions-Policy: identity-credentials-get=(self "https://fedcm-cross-origin-iframe.glitch.me")
You can learn more about how the Permissions Policy works at Controlling browser features with Permissions Policy.