1. Introduction
This section is non-normative.
As the web has evolved there have been ongoing privacy-oriented changes (e.g Safari, Firefox, Chrome) and changes to the underlying privacy principles (e.g. Privacy Model).
With this evolution, fundamental assumptions of the web platform are being redefined or removed. Access to cookies in a third-party context are one of those assumptions. While overall good for the web, the third-party cookie deprecation removes a fundamental building block used by certain designs of federated identity.
The Federated Credential Management API aims to bridge the gap for the federated identity designs which relied on third-party cookies. The API provides the primitives needed to support federated identity when/where it depends on third-party cookies, from sign-in to sign-out and revocation.
In order to provide the federated identity primitives without the use of third-party cookies the API places the user agent as a mediator between a RP (website that requests user information for federated sign in) and an IDP (website that provides user information for federated sign in). This mediation requires user permission before allowing the RPs and IDPs to know about their connection to the user.
The specification leans heavily on changes in the user agent and IDP and minimally on the RP. The FedCM API provides a way to authenticate and fetch tokens.
< html > < head > < title > Welcome to my Website</ title > </ head > < body > < button onclick = "login()" > Login with idp.example</ button > < script > let nonce; async function login() { try { // Assume there is a method returning a random number. Store the value in a variable which can // later be used to check against the value in the token returned. nonce= random(); // Prompt the user to select an account from the IDP to use for // federated login within the RP. If resolved successfully, the Promise // returns an IdentityCredential object from which the |token| can be // extracted. This is an opaque string passed from the IDP to the RP. let token= await navigator. credentials. get({ identity: { providers: [{ configURL: "https://idp.example/manifest.json" , clientId: "123" , nonce: nonce, }] } }); } catch ( e) { // The FedCM call was not successful. } } </ script > </ body > </ html >
At a high level, the Federated Credential Management API works by the intermediation of cooperating IDPs and RPs.
The § 3 Identity Provider HTTP API defines a set of HTTP APIs that IDPs expose as well as the entry points in the § 2 The Browser API that they can use.
The user agent intermediates in such a matter that makes it impractical for the API to be used for tracking purposes, while preserving the functionality of identity federation.
2. The Browser API
The Browser API exposes APIs to RPs and IDPs to call and intermediates the exchange of the user’s identity.
The Sign-up/Sign-in API is used by the RPs to ask the browser to intermediate the relationship with the IDP and the provisioning of a token.
NOTE: The RP makes no delineation between Sign-up and Sign-in, but rather calls the same API indistinguishably.
If all goes well, the Relying Party receives back an IdentityCredential
which contains a token it can use to authenticate the user.
const credential= await navigator. credentials. get({ identity: { providers: [{ configURL: "https://idp.example/manifest.json" , clientId: "123" , }] } });
For fetches that are sent with cookies, unpartitioned cookies are included, as if the resource was loaded as a same-origin request, e.g. regardless of the SameSite value (which is used when a resource loaded as a third-party, not first-party). This makes it easy for an IDP to adopt the FedCM API. It doesn’t introduce security issues on the API because the RP cannot inspect the results from the fetches in any way.
2.1. The Login Status API
2.1.1. Login Status Map
Each user agent keeps a global, persistent Login Status
map, an initially empty map. The keys in this map are origin (of IDPs), and the values are enums that can be one of
"unknown
", "logged-in
",
and "logged-out
".
-
If Login Status map[origin] exists, return it.
-
Otherwise, return unknown.
-
Assert that value is one of logged-in or logged-out.
-
Set Login Status map[origin] to value.
2.1.2. Infrastructure algorithm
true
:
-
If settings’s relevant global object has no associated Document, return
false
. -
Let document be settings’ relevant global object's associated Document.
-
If document has no browsing context, return
false
. -
Let origin be settings’ origin.
-
Let navigable be document’s node navigable.
-
While navigable has a non-null parent:
-
Set navigable to navigable’s parent.
-
If navigable’s active document's origin is not same site with origin, return
false
.
-
-
Return
true
.
2.1.3. HTTP header API
IDPs can set the login status using an HTTP response header as follows.
The HTTP header checking should move into the Fetch spec, since it affects all resource loads.
For each http-redirect fetch and http fetch's response, let value be the result of get a structured field value from the response’s header
list with name "Set-Login
" and type "item
". If value is not null,
process this header as follows:
-
If the request’s destination is not
"document"
:-
If client is null, return.
-
If origin is not same site with the request's origin, return.
-
If client is not same-site with its ancestors, return.
-
-
Assert that value is a tuple.
-
Let token be the first entry of value.
-
If token is
"logged-in"
, set the login status for origin to logged-in. -
If token is
"logged-out"
, set the login status for origin to logged-out.
2.1.4. JavaScript API
IDPs can also use a JavaScript API to update the stored login status:
enum {
LoginStatus ,
"logged-in" , }; [
"logged-out" Exposed =Window ,SecureContext ]interface {
NavigatorLogin Promise <undefined >(
setStatus LoginStatus ); };
status partial interface Navigator { [SecureContext ]readonly attribute NavigatorLogin ; };
login
setStatus()
is called with argument status:
-
If the current settings object is not same-site with its ancestors, throw a
SecurityError
DOMException
. -
Let origin be the current settings object's origin.
-
Let value be logged-in if status is
"logged-in"
or logged-out if status is"logged-out"
. -
Set the login status for origin to value.
2.1.5. Clearing the Login Status Map data
User agents MUST also clear the Login Status map data when:
- the user clears all cookies or site settings data
-
The user agent MUST clear the entire map.
- the user clears all cookies or all site data for a specific origin
-
The user agent MUST remove all entries that would be affected by the deleted cookies, that is, any entry with an origin to which a deleted cookie could be sent to.
Note: For example, domain cookies may affect subdomains of the deleted origin, e.g. clearing cookies for
google.com
should also reset the login status foraccounts.google.com
, since it may rely on a domain cookie for google.com. - the user deletes individual cookies (if allowed by the user agent)
-
the behavior is user agent-defined.
Note: The user agent MAY want to reset the state to unknown, since is impossible to know whether this cookie affects authorization state.
- the user agent receives a Clear-Site-Data header with a
value of
"cookies"
or"*"
, and the request's client is not null, and the client’s origin is same origin with the top-level origin -
while clearing cookies for origin it MUST remove any entries in the Login Status Map where the key is the input origin.
Once Clear-Site-Data supports partitioned cookies, this wording should be updated.
Note: Other website-initiated cookie changes should not affect this map. When IDP login state changes, it should send an explicit Set-Login header. RP state should not affect this map since it only reflects IDP state.
2.2. The connected accounts set
Each user agent has a global connected accounts set, an initially empty ordered set. Its items are triples of the form (rp, idp, account) where rp is the origin of the RP, idp is the origin of the IDP, and account is a string representing an account identifier. It represents the set of triples such that the user has used FedCM to login to the rp via the idp account.
the connected accounts set should be double keyed in the RP (i.e., it should include both the requester and the embedder, or in other words the iframe and the top-level). Otherwise the top-level’s state could be used and modified by the embedder, which introduces leaks and unwanted cross-origin communication.
If a user clears browsing data for an origin (cookies, localStorage, etc.), the user agent MUST remove all triples with an origin matching the origin from connected accounts set.
IdentityProviderConfig
provider, an IdentityProviderAccount
account, and a globalObject, run the following steps. It returns a
triple of the form (rp, idp, account).
IdentityProviderAccount
account is eligible for auto reauthentication given an IdentityProviderConfig
provider and a globalObject, run the following steps. This returns a boolean.
-
If account contains
approved_clients
and account’sapproved_clients
does not contain provider’sclientId
, return false. -
Let triple be the result of running compute the connected account key given provider, account, and globalObject.
-
Return whether connected accounts set contains triple.
IdentityProviderAccount
account, an IdentityProviderConfig
provider and a globalObject, run the following steps.
This returns connected or disconnected.
-
If account contains
approved_clients
:-
If account’s
approved_clients
containsprovider’sclientId
, return connected. -
Return disconnected.
-
-
Let triple be the result of running compute the connected account key given provider, account, and globalObject.
-
If connected accounts set contains triple, return connected.
-
Return disconnected.
IdentityProviderConfig
provider, an IdentityProviderAccount
account, and a globalObject (the RP's), run the following steps:
-
Let configUrl be the result of running parse url with provider’s
configURL
and globalObject. -
Let idpOrigin be the origin corresponding to configUrl.
-
Let rpOrigin be globalObject’s associated Document's origin.
-
Let accountId be account’s
id
. -
Let triple be (rpOrigin, idpOrigin, accountId).
-
Append triple to connected accounts set.
-
Let triple be (rpOrigin, idpOrigin, accountId).
-
If connected accounts set contains triple:
-
Remove triple from the connected accounts set.
-
Return true.
-
-
Return false.
-
For every (rp, idp, accountId) triple in the connected accounts set:
-
If rp equals rpOrigin and idp equals idpOrigin, remove triple from the connected accounts set.
-
2.3. The IdentityCredential Interface
This specification introduces a new type of Credential
, called an IdentityCredential
:
dictionary :
IdentityCredentialDisconnectOptions IdentityProviderConfig {required USVString ; }; [
accountHint Exposed =Window ,SecureContext ]interface :
IdentityCredential Credential {static Promise <undefined >(
disconnect optional IdentityCredentialDisconnectOptions = {});
options readonly attribute USVString ?;
token readonly attribute boolean ; };
isAutoSelected
id
-
The
id
's attribute getter returns the empty string. token
-
The
token
's attribute getter returns the value it is set to. It represents the mintedtoken
provided by the IDP. isAutoSelected
-
isAutoSelected
's attribute getter returns the value it is set to. It represents whether the user’s identity credential was automatically selected when going through the UI flow which resulted in thisIdentityCredential
. [[type]]
-
The
IdentityCredential
's[[type]]
's value is "identity". [[discovery]]
-
The
IdentityCredential
's[[discovery]]
's value isremote
.
The main entrypoint in this specification is through the entrypoints exposed by the Credential Management API.
2.3.1. The disconnect method
disconnect
method is invoked, given an IdentityCredentialDisconnectOptions
options, perform the following steps:
-
Let globalObject be the current global object.
-
Let document be globalObject’s associated Document.
-
If document is not allowed to use the identity-credentials-get policy-controlled feature, throw a "
NotAllowedError
"DOMException
. -
Let promise be a new
Promise
. -
In parallel, attempt to disconnect given options, promise, and globalObject.
-
Return promise.
IdentityCredentialDisconnectOptions
options, a Promise
promise, and a globalObject, perform the following steps:
-
Assert: these steps are running in parallel.
-
Let configUrl be the result of running parse url with options’s
configURL
and globalObject. -
If configUrl is failure, reject promise with an "
InvalidStateError
"DOMException
. -
Run a Content Security Policy Level 3 check with a connect-src directive on the URL passed as configUrl. If it fails, reject promise with a "
NetworkError
"DOMException
. -
If there is another pending
disconnect
call for this globalObject (e.g., it has not yet thrown an exception or its associatedPromise
has not yet been resolved), reject promise with a "NetworkError
"DOMException
. -
If configUrl is not a potentially trustworthy origin, reject promise with a "
NetworkError
"DOMException
. -
If the user has disabled the FedCM API on the globalObject, reject promise with a "
NetworkError
"DOMException
. -
If there does not exist an account account such that connected accounts set contains the result of compute the connected account key given account, options, and globalObject, then reject promise with a "
NetworkError
"DOMException
. This check can be performed by iterating over the connected accounts set or by keeping a separate data structure to make this lookup fast. -
Let config be the result of running fetch the config file with provider and globalObject.
-
If config is failure, reject promise with a "
NetworkError
"DOMException
. -
Let disconnectUrl be the result of computing the manifest URL given provider, config.
disconnect_endpoint
, and globalObject. -
If disconnectUrl is failure, reject promise with a "
NetworkError
"DOMException
. -
Send a disconnect request with disconnectUrl, options, and globalObject, and let result be the result.
-
Let idpOrigin be the origin corresponding to configUrl.
-
Let rpOrigin be globalObject’s associated Document's origin.
-
If result is failure:
-
Remove all connections given rpOrigin and idpOrigin.
-
Reject promise with a "
NetworkError
"DOMException
. -
Return.
-
-
Let accountId be result (note that it is not failure).
-
Remove a connection using accountId, rpOrigin, and idpOrigin, and let wasAccountRemoved be the result.
-
If wasAccountRemoved is false, remove all connections given rpOrigin and idpOrigin.
-
Resolve promise.
2.3.1.1. Disconnect request
The send a disconnect request algorithm sends a request to disconnect an account that has previously been used for federated login in the RP.
IdentityCredentialDisconnectOptions
options, and a globalObject,
perform the following steps. This returns an USVString
or failure.
-
Let requestBody be the result of running urlencoded serializer with a list containing:
-
("client_id", options’s
clientId
) -
("account_hint", options’s
accountHint
)
-
-
Let request be a new request as follows:
- url
-
disconnectUrl
- method
-
"POST"
- body
-
the UTF-8 encode of requestBody
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
-
globalObject’s associated document's origin
- header list
-
a list containing a single header with name set to
Accept
and value set toapplication/x-www-form-urlencoded
- credentials mode
-
"include"
- mode
-
"cors"
-
Let accountId be null.
-
Fetch request with request and globalObject, and with processResponseConsumeBody set to the following steps given a response response and responseBody:
-
Let json be the result of extract the JSON fetch response from response and responseBody.
-
Convert json to a
DisconnectedAccount
, account. -
If one of the previous two steps threw an exception, set accountId to failure and return.
-
Set accountId to account’s
account_id
.
-
-
Wait for accountId to be set.
-
Return accountId.
dictionary {
DisconnectedAccount required USVString account_id ; };
2.3.2. The CredentialRequestOptions
This section defines the dictionaries passed into the JavaScript call:
const credential= await navigator. credentials. get({ identity: { // IdentityCredentialRequestOptions providers: [{ // sequence<IdentityCredentialRequestOptions> configURL: "https://idp.example/manifest.json" , // IdentityProviderConfig.configURL clientId: "123" , // IdentityProviderConfig.clientId nonce: "nonce" // IdentityProviderConfig.nonce }] } });
This specification introduces an extension to the CredentialRequestOptions
object:
partial dictionary CredentialRequestOptions {IdentityCredentialRequestOptions ; };
identity
The IdentityCredentialRequestOptions
contains a list of IdentityProviderConfig
s that the RP supports and has
pre-registered with (i.e. the IDP has given the RP a clientId
).
The IdentityCredentialRequestOptions
also contains a IdentityCredentialRequestOptionsContext
which the user agent can use to provide a more meaningful dialog to users.
enum {
IdentityCredentialRequestOptionsContext ,
"signin" ,
"signup" ,
"use" };
"continue" dictionary {
IdentityCredentialRequestOptions required sequence <IdentityProviderRequestOptions >;
providers IdentityCredentialRequestOptionsContext = "signin"; };
context
Each IdentityProviderConfig
represents an IDP that
the RP supports (e.g. that it has a pre-registration agreement with).
dictionary {
IdentityProviderConfig required USVString ;
configURL required USVString ; };
clientId dictionary :
IdentityProviderRequestOptions IdentityProviderConfig {USVString ;
nonce DOMString ;
loginHint DOMString ; };
domainHint
configURL
-
The URL of the configuration file for the identity provider.
clientId
nonce
-
A random number of the choice of the RP. It is generally used to associate a client session with a
token
and to mitigate replay attacks. Therefore, this value should have sufficient entropy such that it would be hard to guess. loginHint
-
A string representing the login hint corresponding to an account which the RP wants the user agent to show to the user. If provided, the user agent will not show accounts which do not match this login hint value. It generally matches some attribute from the desired
IdentityProviderAccount
. domainHint
-
A string representing the domain hint corresponding to a domain which the RP is interested in, or "any" if the RP wants any account associated with at least one domain hint. If provided, the user agent will not show accounts which do not match the domain hint value.
2.3.3. The [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
internal method
The [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
algorithm runs in parallel inside Credential Management 1 § 2.5.1 Request a Credential to request
credentials and returns an IdentityCredential
or an error.
This internal method accepts three arguments:
origin
-
This argument is the relevant settings object's origin, as determined by the calling
get()
implementation, i.e.,CredentialsContainer
's Request aCredential
abstract operation. options
-
This argument is a
CredentialRequestOptions
object whoseidentity
member exists. sameOriginWithAncestors
-
This argument is a Boolean value which is
true
if and only if the caller’s environment settings object is same-origin with its ancestors. It isfalse
if caller is cross-origin.Note: Invocation of this internal method indicates that it was allowed by permissions policy, which is evaluated at the Credential Management Level 1 level. See § 4 Permissions Policy Integration. As such, sameOriginWithAncestors is unused.
The options.signal
is used as an abort signal for the
requests.
IdentityCredential
's [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
algorithm is invoked, the user agent MUST execute the following steps. This returns an IdentityCredential
(or throws an error to the caller).
-
Assert: These steps are running in parallel.
-
If the size of options["
identity
"]["providers
"] is not equal to 1, queue a global task on the DOM manipulation task source given globalObject to throw a new "NetworkError
"DOMException
Note: The globalObject is not currently passed onto the
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
algorithm. See issue.Support choosing accounts from multiple IDPs, as described here.
-
The user agent can decide when to continue with the next steps.
Note: For example, user agents may show an identity provider selector before making network requests, or provide a button in the URL bar and wait for user input before continuing.
-
Let credential be the result of running create an IdentityCredential with provider, options, and globalObject.
-
If credential is a pair:
-
Let throwImmediately be the value of the second element of the pair.
-
The user agent SHOULD wait a random amount of time before the next step if all of the following conditions hold:
-
throwImmediately is false
-
The promise rejection delay was not disabled by user agent automation
-
The user agent has not implemented another way to prevent exposing to the RP whether the user has an account logged in to the RP
Note: The intention here is as follows. If the the promise was resolved immediately, then an RP could infer that no dialog was shown because the promise was resolved quickly, after just the network delay. A shown dialog implies that the user is logged in to one or more accounts of the IDP. To prevent this information leakage, especially without user confirmation, this delay is specified. However, UAs may have different UI approaches here and prevent it in a different way.
-
-
Queue a global task on the DOM manipulation task source to throw a new "
NetworkError
"DOMException
.
-
-
Otherwise, return credential.
2.3.4. Create an IdentityCredential
The create an IdentityCredential algorithm invokes the various FedCM fetches, shows the user
agent UI, and creates the IdentityCredential
that is then returned to the RP.
IdentityProviderRequestOptions
provider, a CredentialRequestOptions
options, and a globalObject, run the following steps. This returns an IdentityCredential
or a pair (failure, bool), where the bool indicates whether to skip delaying
the exception thrown.
-
Assert: These steps are running in parallel.
-
Let loginStatus be the result of get the login status with the origin of provider’s
configURL
. -
If loginStatus is unknown, a user agent MAY set it to logged-out.
-
If loginStatus is logged-out, the user agent MUST do one of the following:
-
Return (failure, false).
-
Prompt the user whether to continue. If the user continues, the user agent SHOULD set loginStatus to unknown. This MAY include an affordance to show an IDP login dialog.
-
If the user cancels this dialog, return (failure, true).
-
If the user triggers this affordance:
-
Let config be the result of running fetch the config file with provider and globalObject.
-
If config is failure, return (failure, true).
-
Show an IDP login dialog with config and provider.
-
If that algorithm returns failure, return (failure, true).
-
-
We should perhaps provide a way to let the RP request that the second option is provided, possibly gated on a user gesture. See this issue for discussion.
-
-
Let requiresUserMediation be provider’s
configURL
's origin's requires user mediation. -
Let mediation be options’s
mediation
. -
If requiresUserMediation is true and mediation is "
silent
", return (failure, true). -
Let config be the result of running fetch the config file with provider and globalObject.
-
If config is failure, return (failure, false).
-
Fetch accounts step: Let accountsList be the result of fetch the accounts with config, provider, and globalObject.
-
If accountsList is failure, or the size of accountsList is 0:
-
Set the login status for the origin of the
configURL
to logged-out. A user agent may decide to skip this step if no credentials were sent to server.Note: For example, if the fetch failed due to a DNS error, no credentials were sent and therefore the IDP did not learn the user’s identity. In this situation, we do not know whether the user is signed in or not and so we may not want to reset the status.
-
Mismatch dialog step: If loginStatus is logged-in, show a dialog to the user. The contents of this dialog are defined by the user agent. This dialog SHOULD provide an affordance for the user to trigger the show an IDP login dialog algorithm with config and provider; this dialog is the confirm IDP login dialog.
Note: This situation happens when the browser expects the user to be signed in, but the accounts fetch indicated that the user is signed out.
Note: This dialog ensures that silent tracking of the user is impossible by always showing UI of some kind when credentials were sent to the server.
-
Wait until one of the following occurs:
-
If the user closes the dialog, return (failure, true).
-
If the show an IDP login dialog algorithm was triggered:
-
Let result be the result of that algorithm.
-
If result is failure, return (failure, true). The user agent MAY show a dialog to the user before or after returning failure indicating this failure.
-
Otherwise, go back to the fetch accounts step.
-
-
-
-
-
Assert: accountsList is not failure and the size of accountsList is not 0.
-
Set the login status for the origin of the
configURL
to logged-in. -
If provider’s
loginHint
is not empty:-
For every account in accountList, remove account from accountList if account’s
login_hints
does not contain provider’sloginHint
. -
If accountList is now empty, go to the mismatch dialog step.
-
-
If provider’s
domainHint
is not empty:-
For every account in accountList:
-
If
domainHint
is "any":-
If account’s
domain_hints
is empty, remove account from accountList.
-
-
Otherwise, remove account from accountList if account’s
domain_hints
does not contain provider’sdomainHint
.
-
-
If accountList is now empty, go to the mismatch dialog step.
-
-
For each acc in accountsList:
-
If acc["
picture
"] is present, fetch the account picture with acc and globalObject.
Note: The user agent may choose to show UI which does not initially require fetching the account pictures. In these cases, the user agent may delay these fetches until they are needed. Because errors from these fetches are ignored, they can happen in any order.
-
-
Let registeredAccount, numRegisteredAccounts be null and 0, respectively.
-
Let account be null.
-
For each acc in accountsList:
-
If acc is eligible for auto reauthentication given provider, and globalObject, set registeredAccount to acc and increase numRegisteredAccounts by 1.
-
-
Let permission, disclosureTextShown, and isAutoSelected be set to false.
-
If mediation is not "
required
", requiresUserMediation is false, and numRegisteredAccounts is equal to 1:-
Set account to registeredAccount and permission to true. When doing this, the user agent MAY show some UI to the user indicating that they are being auto-reauthenticated.
-
Set isAutoSelected to true.
-
-
Otherwise, if mediation is "
silent
", return (failure, true). -
Otherwise, if accountsList’s size is 1:
-
Set account to accountsList[0].
-
If compute the connection status of account, provider and globalObject returns connected, show a dialog to request user permission to sign in via account, and set the result in permission. The user agent MAY use options’s
context
to customize the dialog. -
Otherwise, let permission be the result of running request permission to sign-up algorithm with account, config, provider, and globalObject. Also set disclosureTextShown to true.
-
-
Otherwise:
-
Set account to the result of running the select an account from the accountsList.
-
If account is failure, return (failure, true).
-
If compute the connection status of account, provider and globalObject is connected, set permission to true.
-
Otherwise:
-
Let permission be the result of running the request permission to sign-up algorithm with account, config, provider, and globalObject.
-
Set disclosureTextShown to true.
-
-
-
Wait until the user agent's dialogs requesting for user choice or permission to be closed, if any are created in the previous steps.
-
Assert: account is not null.
-
If permission is false, then return (failure, true).
-
Let credential be the result of running the fetch an identity assertion algorithm with account’s
id
, disclosureTextShown, isAutoSelected, provider, config, and globalObject. -
Return credential.
2.3.5. Fetch the config file
The fetch the config file algorithm fetches both the well-known file and the config file from the IDP, checks that the config file is mentioned in the well-known file, and returns the config.
IdentityProviderRequestOptions
provider and globalObject, run the following steps. This returns an IdentityProviderAPIConfig
or failure.
-
Let configUrl be the result of running parse url with provider’s
configURL
and globalObject. -
If configUrl is failure, return failure.
-
Run a Content Security Policy Level 3 check with a connect-src directive on the URL passed as configUrl. If it fails, return failure.
-
If configUrl is not a potentially trustworthy URL, return failure.
-
Let rootUrl be a new URL.
-
Set rootUrl’s host to configUrl’s host's registrable domain.
-
Set rootUrl’s path to the list «".well-known", "web-identity"».
-
Let config, configInWellKnown both be null.
-
Let rpOrigin be globalObject’s associated Document's origin.
-
If rpOrigin is not an opaque origin, and rootUrl’s host is equal to rpOrigin’s registrable domain, and rootUrl’s scheme is equal to rpOrigin’s scheme, set configInWellKnown to true.
Note: Because domain cookies are valid across an entire site, there is no privacy benefit from doing the well-known check if the RP and IDP are in the same site.
-
Otherwise:
-
Let wellKnownRequest be a new request as follows:
- URL
-
rootUrl
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
-
a unique opaque origin
- header list
-
a list containing a single header with name set to
Accept
and value set toapplication/json
- referrer policy
-
"no-referrer"
- credentials mode
-
"omit"
- mode
-
"no-cors"
The spec is yet to be updated so that all requests are created with mode set to "user-agent-no-cors". See the relevant pull request for details.
-
Fetch request with wellKnownRequest and globalObject, and with processResponseConsumeBody set to the following steps given a response response and responseBody:
-
Let json be the result of extract the JSON fetch response from response and responseBody.
-
Convert json to an
IdentityProviderWellKnown
, discovery. -
If one of the previous two steps threw an exception, or if the size of discovery["
provider_urls
"] is greater than 1, set configInWellKnown to false.relax the size of the provider_urls array.
-
Otherwise, set to configInWellKnown to true if discovery["
provider_urls
"][0] is equal to provider’sconfigURL
, and to false otherwise.
-
-
-
Let configRequest be a new request as follows:
- url
-
configUrl
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
-
a unique opaque origin
- header list
-
a list containing a single header with name set to
Accept
and value set toapplication/json
- referrer policy
-
"no-referrer"
- credentials mode
-
"omit"
- mode
-
"no-cors"
The spec is yet to be updated so that all requests are created with mode set to "user-agent-no-cors". See the relevant pull request for details.
-
Fetch request with configRequest and globalObject, and with processResponseConsumeBody set to the following steps given a response response and responseBody:
-
Let json be the result of extract the JSON fetch response from response and responseBody.
-
Convert json to an
IdentityProviderAPIConfig
stored in config. -
If one of the previous two steps threw an exception, set config to failure.
-
Set config.
login_url
to the result of computing the manifest URL with provider, config and globalObject. -
If config.
login_url
is null, return failure.
-
-
Wait for both config and configInWellKnown to be set.
-
If configInWellKnown is true, return config. Otherwise, return failure.
NOTE: a two-tier file system is used in order to prevent the IDP from easily determining the RP that a user is visiting by encoding the information in the config file path. This issue is solved by requiring a well-known file to be on the root of the IDP. The config file itself can be anywhere, but it will not be used if the user agent does not find it in the well-known file. This allows the IDP to keep their actual config files on an arbitary path while allowing the user agent to prevent config file path manipulation to fingerprint (for instance, by including the RP in the path). See § 7.3.1 Manifest Fingerprinting.
dictionary {
IdentityProviderWellKnown required sequence <USVString >provider_urls ; };dictionary {
IdentityProviderIcon required USVString url ;unsigned long size ; };dictionary {
IdentityProviderBranding USVString background_color ;USVString color ;sequence <IdentityProviderIcon >icons ;USVString name ; };dictionary {
IdentityProviderAPIConfig required USVString accounts_endpoint ;required USVString client_metadata_endpoint ;required USVString id_assertion_endpoint ;required USVString ;
login_url USVString disconnect_endpoint ;IdentityProviderBranding branding ; };
2.3.6. Fetch the accounts
The fetch the accounts algorithm fetches the accounts endpoint to determine the list of IDP accounts that the user is signed in to, so that the user agent can later show the FedCM UI to the user.
IdentityProviderAPIConfig
config, an IdentityProviderRequestOptions
provider, and globalObject, run the following steps. This
returns an IdentityProviderAccountList
.
-
Let accountsUrl be the result of computing the manifest URL given provider, config["
accounts_endpoint
"], and globalObject. -
If accountsUrl is failure, return an empty list.
-
Let request be a new request as follows:
- url
-
accountsUrl
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
-
a unique opaque origin
- header list
-
a list containing a single header with name set to
Accept
and value set toapplication/json
- referrer policy
-
"no-referrer"
- credentials mode
-
"include"
- mode
-
"no-cors"
The credentialed fetch in this algorithm can lead to a timing attack that leaks the user’s identities before the user grants permission. This is an active area of investigation that is being explored here.
The spec is yet to be updated so that all requests are created with mode set to "user-agent-no-cors". See the relevant pull request for details.
-
Let accountsList be null.
-
Fetch request with request and globalObject, and with processResponseConsumeBody set to the following steps given a response response and responseBody:
-
Let json be the result of extract the JSON fetch response from response and responseBody.
-
Convert json to an
IdentityProviderAccountList
, and store the result in accountsList. -
If one of the previous two steps threw an exception, set accountsList to failure.
the accounts list returned here should be validated for repeated ids, as described here.
-
-
Wait for accountsList to be set.
-
Return accountsList.
dictionary {
IdentityProviderAccount required USVString id ;required USVString name ;required USVString USVString given_name ;USVString picture ;sequence <USVString >approved_clients ;sequence <DOMString >login_hints ;sequence <DOMString >domain_hints ; };dictionary {
IdentityProviderAccountList sequence <IdentityProviderAccount >; };
accounts
IdentityProviderAccount
account and a globalObject, run the following steps:
-
Let pictureUrl be the result of running parse url with account["
picture
"] and globalObject. -
If pictureUrl is failure, abort these steps. The user agent may use a placeholder image.
-
Let pictureRequest be a new request as follows:
- url
-
pictureUrl
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"image"
- origin
-
a unique opaque origin
- referrer policy
-
"no-referrer"
- credentials mode
-
"omit"
- mode
-
"no-cors"
The spec is yet to be updated so that all requests are created with mode set to "user-agent-no-cors". See the relevant pull request for details.
-
Fetch request with pictureRequest and globalObject, and with processResponseConsumeBody set to the following steps given a response and a responseBody:
-
If responseBody is null or failure, the user agent may choose an arbitrary placeholder image and associate it with the account.
-
Otherwise, decode responseBody into an image, and associate it with account if successful. This allows the user agent to use the decoded image in a dialog displaying account.
-
2.3.7. Fetch an identity assertion
The fetch an identity assertion algorithm is invoked after the user has granted permission to use FedCM with a specific IDP account. It fetches the identity assertion endpoint to obtain the token that will be provided to the RP.
USVString
accountId, a boolean disclosureTextShown, a boolean isAutoSelected, an IdentityProviderRequestOptions
provider, an IdentityProviderAPIConfig
config,
and globalObject, run the following steps. This returns an IdentityCredential
or failure.
-
Let tokenUrl be the result of computing the manifest URL given provider, config["
id_assertion_endpoint
"], and globalObject. -
If tokenUrl is failure, return failure.
-
Let requestBody be the result of running urlencoded serializer with a list containing:
-
Let request be a new request as follows:
- url
-
tokenUrl
- method
-
"POST"
- body
-
the UTF-8 encode of requestBody
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
-
globalObject’s associated document's origin
- header list
-
a list containing a single header with name set to
Accept
and value set toapplication/x-www-form-urlencoded
- credentials mode
-
"include"
- mode
-
"cors"
-
Let credential be null.
-
Fetch request with request and globalObject, and with processResponseConsumeBody set to the following steps given a response response and responseBody:
-
Let json be the result of extract the JSON fetch response from response and responseBody.
-
Convert json to an
IdentityProviderToken
, token. -
If one of the previous two steps threw an exception, set credential to failure and return.
-
Let credential be a new
IdentityCredential
given globalObject’s realm. -
Set credential’s
token
to token. -
Set credential’s
isAutoSelected
to isAutoSelected.
-
-
Wait for credential to be set.
-
Return credential.
dictionary {
IdentityProviderToken required USVString token ; };
2.3.8. Request permission to sign-up
IdentityProviderAccount
or failure.
-
Assert accountsList’s size is greater than 1.
-
Display an account chooser displaying the options from accountsList.
-
Let account be the
IdentityProviderAccount
of the account that the user manually selects from the accounts chooser, or failure if no account is selected. -
Return account.
The request permission to sign-up algorithm fetches the client metadata endpoint of the RP, waits for the user to grant permission to use the given account, and returns whether the user granted permission or not.
IdentityProviderAccount
account,
an IdentityProviderAPIConfig
config, an IdentityProviderRequestOptions
provider, and a globalObject, run the following steps. This returns a boolean.
-
Assert: These steps are running in parallel.
-
Let metadata be the result of running fetch the client metadata with config, provider, and globalObject.
-
Prompt the user to gather explicit intent to create an account. The user agent MAY use the
IdentityProviderBranding
to inform the style choices of its UI. Additionally:-
If metadata is not failure, metadata["
privacy_policy_url
"] is defined and the provider’sclientId
is not in the list of account["approved_clients
"], then the user agent MUST display the metadata["privacy_policy_url
"] link. -
If metadata is not failure, metadata["
terms_of_service_url
"] is defined, and the provider’sclientId
is not in the list of account["approved_clients
"], then the user agent MUST display the metadata["terms_of_service_url
"] link. -
The user agent MAY use the
context
to customize the dialog shown.
-
-
If the user does not grant permission, return false.
-
Create a connection between the RP and the IdP account with provider, account, and globalObject.
-
Return true.
IdentityProviderAPIConfig
config and
an IdentityProviderRequestOptions
provider, run the following steps. This returns an IdentityProviderClientMetadata
or failure.
-
Let clientMetadataUrl be the result of computing the manifest URL given provider, config["
client_metadata_endpoint
"], and globalObject. -
If clientMetadataUrl is failure, return failure.
-
Let request be a new request as follows:
- url
-
clientMetadataUrl
- redirect mode
-
"error"
- client
-
null
- window
-
"no-window"
- service-workers mode
-
"none"
- destination
-
"webidentity"
- origin
-
globalObject’s associated document's origin
- header list
-
a list containing a single header with name set to
Accept
and value set toapplication/json
- credentials mode
-
"omit"
- mode
-
"no-cors"
The spec is yet to be updated so that all requests are created with mode set to "user-agent-no-cors". See the relevant pull request for details.
-
Let metadata be null.
-
Fetch request with request and globalObject, and with processResponseConsumeBody set to the following steps given a response response and responseBody:
-
Let json be the result of extract the JSON fetch response from response and responseBody.
-
Convert json to an
IdentityProviderClientMetadata
, and store the result in metadata. -
If one of the previous two steps threw an exception, set metadata to failure.
-
-
Wait until metadata is set.
-
Return metadata.
dictionary {
IdentityProviderClientMetadata USVString privacy_policy_url ;USVString terms_of_service_url ; };
2.3.9. Helper algorithms
The following helper algorithms are used during the FedCM flow.
USVString
stringUrl, a globalObject, and an optional baseUrl (default null), run the following steps. This returns a URL or failure.
-
Let configUrl be null.
-
Queue a global task on the DOM manipulation task source given globalObject to set configUrl to the result of running url parser with stringUrl and baseUrl.
Note: a task is queued since the url parser needs to be run within a task, not in parallel.
-
Wait for configUrl to be set.
-
Return configUrl.
-
Queue a global task on the network task source given globalObject to:
-
Fetch request with processResponseConsumeBody set to processResponseConsumeBody.
-
Note: a task is queued since the fetch needs to be run within a task, not in parallel.
IdentityProviderRequestOptions
provider, a string manifestString, and globalObject, perform the following steps. This returns a URL or failure.
-
Let configUrl be the result of running parse url with provider’s
configURL
and globalObject. -
Let manifestUrl be the result of running parse url given manifestString (the relative URL), globalObject, and configUrl (the base URL).
-
Wait until manifestUrl is set.
Note: This means that passing the manifest string as either an absolute or relative URL is allowed.
-
If manifestUrl is failure, return failure.
-
If manifestUrl is not same origin with configUrl, return failure.
-
If manifestUrl is not a potentially trustworthy URL, return failure.
-
Return manifestUrl.
-
Assert: These steps are running on the networking task source.
-
If response is a network error or its status is not an ok status, throw a new "
NetworkError
"DOMException
. -
Let mimeType be the result of extracting a MIME TYPE from response’s header list.
-
If mimeType is failure or is not a JSON MIME Type, throw a new "
NetworkError
"DOMException
. -
Let json be the result of parse JSON bytes to a JavaScript value passing responseBody.
-
If json is a parsing exception, throw a new "
NetworkError
"DOMException
. -
Return json.
IdentityProviderAPIConfig
config, an IdentityProviderConfig
provider, and a globalObject, run the following steps. This returns
success or failure.
-
Assert: these steps are running in parallel.
-
Let loginUrl be null.
-
Queue a global task on the DOM manipulation task source given globalObject to set loginUrl to the result of running url parser with config.
login_url
. -
Wait until loginUrl is not null.
-
Assert: loginUrl is not failure (the user agent has previously checked that config.
login_url
is a valid URL). -
Let queryList be a new list.
-
If provider’s
loginHint
is not empty, append ("login_hint",loginHint
) to queryList. -
If provider’s
domainHint
is not empty, append ("domain_hint",domainHint
) to queryList. -
If queryList is not empty:
-
Let queryParameters be the result of the urlencoded serializer with queryList.
-
If loginUrl’s query is not null or empty, prepend "&" to queryParameters.
-
Append queryParameters to loginUrl’s query.
-
-
Create a fresh top-level traversable with loginUrl.
-
The user agent MAY set up browsing context features or otherwise affect the presentation of this traversable in an implementation-defined way.
-
Wait for one of the following conditions:
-
The user closes the browsing context: return failure.
-
IdentityProvider
.close
is called in the context of this new traversable:-
Close the traversable.
-
Let loginStatus be the result of get the login status with the origin of the
login_url
.Note: The IDP login flow may set this value to logged-in using either the JavaScript or HTTP header API during the login flow. It is also possible that this change happened in a different browsing context.
-
If loginStatus is logged-in, return success.
-
Otherwise, return failure.
-
-
2.4. The IdentityProvider Interface
This specification introduces the IdentityUserInfo
dictionary as well as the IdentityProvider
interface:
dictionary {
IdentityUserInfo USVString ;
USVString ;
name USVString ;
givenName USVString ; }; [
picture Exposed =Window ,SecureContext ]interface {
IdentityProvider static undefined ();
close static Promise <sequence <IdentityUserInfo >>(
getUserInfo IdentityProviderConfig ); };
config
Decide whether IdentityProvider
is the
correct location for the getUserInfo()
method.
A close
function is provided to signal to the browser that
the login flow is finished. The reason for this function in addition to the
header is that even when the user is already logged in, the login flow may not
be finished yet; for example, an IDP may want to prompt the user to verify
their phone number. To allow for such flows, the IDP must call close
when the flow is fully done.
See the show an IDP login dialog algorithm for more details.
An IdentityUserInfo
represents user account information from a user. This information is exposed
to the IDP once the user has already used the FedCM API to login in the RP. That is, it is
exposed when there exists an account account such that the connected accounts set contains the triple (RP, IDP, account). The information matches what is received from the accounts endpoint. The IDP can obtain this information by invoking the getUserInfo()
static method from an iframe matching the origin of its configURL
.
const userInfo= await IdentityProvider. getUserInfo({ configUrl: "https://idp.example/fedcm.json" , clientId: "client1234" }); if ( userInfo. length> 0 ) { // It’s up to the IDP regarding how to display the returned accounts. const name= userInfo[ 0 ]. name; const givenName= userInfo[ 0 ]. givenName; const displayName= givenName? givenName: name; const picture= userInfo[ 0 ]. picture; const email= userInfo[ 0 ]. email; }
getUserInfo()
method given an IdentityProviderConfig
provider, perform the following steps:
-
Let globalObject be the current global object.
-
Let document be globalObject’s associated Document.
-
If document is not allowed to use the identity-credentials-get policy-controlled feature, throw a "
NotAllowedError
"DOMException
. -
If there does not exist an account account such that connected accounts set contains the result of compute the connected account key given account, provider, and globalObject, then reject promise with a "
NetworkError
"DOMException
. This check can be performed by iterating over the connected accounts set or by keeping a separate data structure to make this lookup fast. -
Let configUrl be the result of running parse url with provider’s
configURL
and globalObject. -
If configUrl is failure, throw an "
InvalidStateError
"DOMException
. -
If document’s origin is not same origin as configUrl’s origin, throw an "
InvalidStateError
"DOMException
. -
Run a Content Security Policy Level 3 check with a connect-src directive on the URL passed as configUrl. If it fails, throw a new "
NetworkError
"DOMException
. -
If globalObject’s navigable is a top-level traversable, throw a new "
NetworkError
"DOMException
. -
If the user has disabled the FedCM API on the globalObject’s navigable's top-level traversable, throw a new "
NetworkError
"DOMException
. -
Let promise be a new
Promise
. -
Perform the following steps in parallel:
-
Let config be the result of running fetch the config file with provider and globalObject.
-
If config is failure, reject promise with a new "
NetworkError
"DOMException
. -
Let accountsList be the result of fetch the accounts with config, provider, and globalObject.
-
Let hasAccountEligibleForAutoReauthentication be false.
-
For each account in accountsList:
-
If account["
approved_clients
"] is not empty and it does not contain provider’sclientId
, continue.Note: this allows the IDP to override whether an account is a returning account. This could be useful for instance in cases where the user has disconnected the account out of band.
-
If account is eligible for auto reauthentication given provider and globalObject, set hasAccountEligibleForAutoReauthentication to true.
-
-
If hasAccountEligibleForAutoReauthentication is false, reject promise with a new "
NetworkError
"DOMException
. -
Let userInfoList be a new list.
-
For each account in accountsList:
-
Append an
IdentityUserInfo
to userInfoList with the following values:
-
-
3. Identity Provider HTTP API
This section is non-normative.
The IDP exposes a series of HTTP endpoints:
-
§ 3.1 The Well-Known File that points to a Manifest
-
A § 3.2 The config file in an agreed upon location that points to
-
An § 3.3 Accounts endpoint endpoint
-
A § 3.4 Client Metadata endpoint
-
An § 3.5 Identity assertion endpoint endpoint
-
An § 3.6 Disconnect endpoint endpoint if it supports
disconnect
.
The FedCM API introduces the ability for a site to ask the browser to execute a few different network requests. It is important for the browser to execute these in such a way that it does not allow the user to be tracked (by an attacker impersonating an IDP) on to the site using FedCM. The following table has information about the network requests performed:
Endpoint | cookies | client_id | origin |
manifests | no | no | no |
accounts_endpoint | yes | no | no |
client_metadata_endpoint | no | yes | yes |
id_assertion_endpoint | yes | yes | yes |
disconnect_endpoint | yes | yes | yes |
3.1. The Well-Known File
NOTE: The browser uses the well-known file to prevent § 7.3.1 Manifest Fingerprinting.
The IDP exposes a well-known file in a pre-defined location, specifically at the "web-identity" file at the IDPs's path ".well-known".
The well-known file is fetched in the fetch the config file algorithm:
(a) without cookies,
(b) with the Sec-Fetch-Dest header set to webidentity
, and
(c) without revealing the RP in the Origin or Referer headers.
For example:
GET /.well-known/web-identity HTTP / 1.1 Host : idp.example Accept : application/json Sec-Fetch-Dest : webidentity
The file is parsed expecting a IdentityProviderWellKnown
JSON object.
The IdentityProviderWellKnown
JSON object has the following semantics:
provider_urls
(required), of type sequence<USVString>-
A list of URLs that points to valid § 3.2 The config files.
3.2. The config file
The config file serves as a discovery device to other endpoints provided by the IDP.
The config file is fetched in the fetch the config file algorithm:
(a) without cookies,
(b) with the Sec-Fetch-Dest header set to webidentity
,
(c) without revealing the RP in the Origin or Referer headers, and
(d) without following HTTP redirects.
For example:
The response body must be a JSON object that can be converted to an IdentityProviderAPIConfig
without an exception.
The IdentityProviderAPIConfig
object’s members have the following semantics:
accounts_endpoint
, of type USVString-
A URL that points to an HTTP API that complies with the § 3.3 Accounts endpoint API.
client_metadata_endpoint
, of type USVString-
A URL that points to an HTTP API that complies with the § 3.4 Client Metadata API.
id_assertion_endpoint
, of type USVString-
A URL that points to an HTTP API that complies with the § 3.5 Identity assertion endpoint API.
disconnect_endpoint
, of type USVString-
A URL that points to an HTTP API that complies with the § 3.6 Disconnect endpoint API.
branding
, of type IdentityProviderBranding-
A set of
IdentityProviderBranding
options.
The IdentityProviderBranding
enables an IDP to express their branding
preferences, which may be used by user agents to customize the permission prompt.
Note: The branding preferences are deliberately designed to be high level / abstract (rather than opinionated about a specific UI structure), to enable different user agents to offer different UI experiences and for them to evolve independently over time.
Its members have the following semantics:
background_color
, of type USVStringcolor
, of type USVStringicons
, of type sequence<IdentityProviderIcon>-
A list of
IdentityProviderIcon
objects. name
, of type USVString-
A user-recognizable name for the IDP.
Note: The branding preferences are deliberately designed to be high level / abstract (rather than opinionated about a specific UI structure), to enable different user agents to offer different UI experiences and for them to evolve independently over time.
The IdentityProviderIcon
has members with the following semantics:
url
, of type USVString-
The url pointing to the icon image, which must be square and single resolution (not a multi-resolution .ico). The icon needs to comply with the maskable specification.
size
, of type unsigned long-
The width/height of the square icon. The size may be omitted if the icon is in a vector graphic format (like SVG).
Note: the user agent reserves a square size for the icons provided by the developer. If the developer provides an icon that is not square, the user agent may choose to not display it at all, trim the icon and show a square portion of it, or even transform it into a square icon and show that.
The color is a subset of CSS <color> syntax, namely <hex-color>s, hsl()s, rgb()s and <named-color>.
For example:
{ "accounts_endpoint" : "/accounts" , "client_metadata_endpoint" : "/metadata" , "id_assertion_endpoint" : "/assertion" , "disconnect_endpoint" : "/disconnect" , "branding" : { "background_color" : "green" , "color" : "#FFEEAA" , "icons" : [{ "url" : "https://idp.example/icon.ico" , "size" : 25 }], "name" : "IDP Example" } }
3.3. Accounts endpoint
The accounts endpoint provides the list of accounts the user has at the IDP.
The accounts endpoint is fetched in the fetch the accounts algorithm:
(a) with IDP cookies,
(b) with the Sec-Fetch-Dest header set to webidentity
,
(c) without revealing the RP in the Origin or Referer headers, and
(d) without following HTTP redirects.
For example:
GET /accounts_list HTTP / 1.1 Host : idp.example Accept : application/json Cookie : 0x23223 Sec-Fetch-Dest : webidentity
The response body must be a JSON object that can be converted to an IdentityProviderAccountList
without an exception.
Every IdentityProviderAccount
is expected to have members with the following semantics:
id
, of type USVString-
The account unique identifier.
name
, of type USVString-
The user’s full name.
email
, of type USVString-
The user’s email address.
given_name
, of type USVString-
The user’s given name.
picture
, of type USVString-
URL for the account’s picture.
approved_clients
, of type sequence<USVString>-
A list of RPs (that gets matched against the requesting
clientId
) this account is already registered with. Used in the request permission to sign-up to allow the IDP to control whether to show the Privacy Policy and the Terms of Service. login_hints
, of type sequence<DOMString>-
A list of strings which correspond to all of the login hints which match with this account. An RP can use the
loginHint
to request that only an account matching a given value is shown to the user. domain_hints
, of type sequence<DOMString>-
A list of strings which correspond to all of the domain hints which match with this account. An RP can use the
domainHint
to request that only an account matching a given value or containing some domain hint is shown to the user.
For example:
{ "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" : [ "john_doe" ], "domain_hints" : [ "idp.example" ], }, { "id" : "5678" , "given_name" : "Johnny" , "name" : "Johnny" , "email" : "johnny@idp.example" , "picture" : "https://idp.example/profile/456" , "approved_clients" : [ "abc" , "def" , "ghi" ], "login_hints" : [ "email=johhny@idp.example" , "id=5678" ], "domain_hints" : [ "idp.example" ], }] }
Clarify the IDP API response when the user is not signed in.
3.4. Client Metadata
The client metadata endpoint provides metadata about RPs.
The client metadata endpoint is fetched in the fetch the client metadata algorithm:
(a) without cookies,
(b) with the Sec-Fetch-Dest header set to webidentity
,
(c) with the RP's origin in the Origin header, and
(d) without following HTTP redirects.
The user agent also passes the client_id.
For example:
GET /client_medata?client_id=1234 HTTP / 1.1 Host : idp.example Origin : https://rp.example/ Accept : application/json Sec-Fetch-Dest : webidentity
The response body must be a JSON object that can be converted to an IdentityProviderClientMetadata
without an exception.
The IdentityProviderClientMetadata
object’s members have the following semantics:
privacy_policy_url
, of type USVString-
A link to the RP's Privacy Policy.
terms_of_service_url
, of type USVString-
A link to the RP's Terms of Service.
For example:
{ "privacy_policy_url" : "https://rp.example/clientmetadata/privacy_policy.html" , "terms_of_service_url" : "https://rp.example/clientmetadata/terms_of_service.html" }
3.5. Identity assertion endpoint
The identity assertion endpoint is responsible for minting a new token that contains signed assertions about the user.
The identity assertion endpoint is fetched in the fetch an identity assertion algorithm:
(a) as a POST request,
(b) with IDP cookies,
(c) with the RP's origin in the Origin header, and
(d) with the Sec-Fetch-Dest header set to webidentity
,
(e) without following HTTP redirects.
It will also contain the following parameters in the request body application/x-www-form-urlencoded
:
client_id
nonce
-
The request nonce
account_id
-
The account identifier that was selected.
disclosure_text_shown
-
Whether the user agent has explicitly shown to the user what specific information the IDP intends to share with the RP (e.g. "idp.example will share your name, email... with rp.example"), used by the request permission to sign-up algorithm for new users. It is used as an assurance by the user agent to the IDP that it has indeed shown the terms of service and privacy policy to the user in the cases where it is required to do so.
For example:
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=Ct60bD&disclosure_text_shown=true
clientId
. As the clientId
are IDP-specific, the user agent cannot perform this check. The response body must be a JSON object that can be converted to an IdentityProviderToken
without an exception.
Every IdentityProviderToken
is expected to have members with the following semantics:
token
, of type USVString-
The resulting token.
The content of the token
is opaque to the user agent and can contain
anything that the IDP would like to pass to the RP to facilitate the login. For this reason the RP is expected to be the party responsible for validating the token
passed
along from the IDP using the appropriate token validation
algorithms defined. One example of how this might be done is defined
in OIDC Connect Core § IDTokenValidation.
NOTE: For IDPs, it is worth considering how portable accounts are. Portability is left entirely up to IDPs, who can choose between a variety of different mechanisms to accomplish it (e.g. OIDC’s Account Porting).
For example:
3.6. Disconnect endpoint
The disconnect endpoint is responsible for disconnecting a previously made federated
login connection between an RP and an IDP account, and returning the account’s id
so that the user agent can remove it from the connected accounts set.
The disconnect endpoint is fetched when invoking the disconnect
method:
(a) as a POST request,
(b) with IDP cookies,
(c) with the RP's origin in the Origin header,
(d) with the Sec-Fetch-Dest header set to webidentity
,
(e) without following HTTP redirects, and
(f) in "cors" mode.
It will also contain the following in the request body application/x-www-form-urlencoded
:
For example:
POST /fedcm_disconnect_endpoint HTTP / 1.1 Host : idp.example Origin : https://rp.example/ Content-Type : application/x-www-form-urlencoded Cookie : 0x23223 Sec-Fetch-Dest : webidentity client_id=client1234&account_hint=hint12
If the disconnection is unsuccessful, the IDP may respond with an error. If it is successful,
the response body must be a JSON object that can be converted to an DisconnectedAccount
without an exception.
account_id
, of type USVString-
The
id
of the account that was successfully disconnected.
The IDP must return the account_id
since it may be different from the account_hint
, and the ID is the one which allows the user agent to disconnect the account from the connected accounts set. If the IDP returns an error or
the user agent does not find the account with the ID provided by the IDP, then all accounts
associated with the relevant (RP, IDP) are removed from the connected accounts set.
4. Permissions Policy Integration
FedCM defines a policy-controlled feature identified by the string "identity-credentials-get"
.
Its default allowlist is "self"
.
A Document
’s permissions policy determines whether any content
in that document is allowed to obtain a credential object using the Browser API.
Attempting to invoke navigator.credentials.get({identity:..., ...})
in documents that are not allowed to use the identity-credentials-get feature will result
in a promise rejected with a "NotAllowedError
" DOMException
.
This restriction can be controlled using the mechanisms described in Permissions Policy.
Note: Algorithms specified in Credential Management Level 1 perform the actual
permissions policy evaluation. This is because such policy evaluation needs to
occur when there is access to the current settings object. The internal methods
modified by this specification do not have such access since they are invoked in parallel by CredentialsContainer
's Request a Credential
abstract operation.
5. User Agent Automation
For the purposes of user agent automation and website testing, this document defines the below WebDriver extension commands to interact with any active FedCM dialogs.
5.1. Extension capability
In order to advertise the availability of the extension commands defined below, a new extension capability is defined.
Capability | Key | Value Type | Description |
---|---|---|---|
Federated Credential Management Support | "fedcm:accounts"
| boolean | Indicates whether the endpoint node supports all Federated Credential Management commands. |
When validating capabilities, the extension-specific substeps to validate "fedcm:accounts"
with value
are the following:
-
If
value
is not a boolean return a WebDriver Error with error code invalid argument. -
Otherwise, let
deserialized
be set tovalue
.
When matching capabilities, the extension-specific steps to match "fedcm:accounts"
with value
are the following:
-
If
value
istrue
and the endpoint node does not support any of the Federated Credential Management commands, the match is unsuccessful. -
Otherwise, the match is successful.
5.2. Cancel dialog
HTTP Method | URI Template |
---|---|
POST | /session/{session id}/fedcm/canceldialog
|
The remote end steps are:
-
If no FedCM dialog is currently open, return a WebDriver error with error code no such alert.
-
Close the dialog and continue the create an IdentityCredential algorithm as if the user had canceled the dialog without choosing an account.
-
Return success with data
null
.
5.3. Select account
HTTP Method | URI Template |
---|---|
POST | /session/{session id}/fedcm/selectaccount
|
The remote end steps are:
-
If parameters is not a JSON Object, return a WebDriver error with error code invalid argument.
-
If no FedCM dialog is currently open, return a WebDriver error with error code no such alert.
-
Let accountIndex be the result of getting a property named
"accountIndex"
from parameters. -
If accountIndex is
undefined
or is less than 0 or greater than or equal to the number of accounts that the user can choose from in the current flow, return a WebDriver error with error code invalid argument. -
Close the dialog and continue the create an IdentityCredential algorithm as if the user had selected the account indicated by accountIndex and granted permission to sign-up, if applicable.
-
Return success with data
null
.
5.4. Click dialog button
HTTP Method | URI Template |
---|---|
POST | /session/{session id}/fedcm/clickdialogbutton
|
The remote end steps are:
-
If parameters is not a JSON Object, return a WebDriver error with error code invalid argument.
-
Let dialogButton be the result of getting a property named
"dialogButton"
from parameters. -
If dialogButton is not a string that is "
ConfirmIdpLoginContinue
", return a WebDriver error with error code invalid argument. -
If no FedCM dialog is currently open or the dialog is not a confirm IDP login dialog, return a WebDriver error with error code no such alert.
-
Act as if the user had clicked the "continue" button in the confirm IDP login dialog and initiate the login flow.
-
Return success with data
null
.
5.5. Account list
HTTP Method | URI Template |
---|---|
GET | /session/{session id}/fedcm/accountlist
|
The remote end steps are:
-
If no FedCM dialog is currently open, return a WebDriver error with error code no such alert.
-
Let accounts be the list of accounts that the user can or could choose from in the current flow.
-
Let list be an empty list.
-
For each account in accounts:
-
Let accountState be the result of running the compute the connection status algorithm given account and the
IdentityProviderRequestOptions
of the IDP account belongs to -
Append a dictionary to list with the following properties:
-
accountId
set to the account’sid
-
email
set to the account’semail
-
name
set to the account’sname
-
givenName
set to the account’sgiven_name
, if present -
pictureUrl
set to the account’spicture
, if present -
idpConfigUrl
set to theconfigURL
of the IDP this account belongs to -
loginState
to"SignUp"
if accountState is disconnected and"SignIn"
otherwise -
termsOfServiceUrl
to theterms_of_service_url
if one was provided and theloginState
is"SignUp"
, otherwiseundefined
-
privacyPolicyUrl
to theprivacy_policy_url
if one was provided and theloginState
is"SignUp"
, otherwiseundefined
-
-
-
Return success with data list.
5.6. Get title
HTTP Method | URI Template |
---|---|
GET | /session/{session id}/fedcm/gettitle
|
Note: This command lets automation verify that the context api was applied properly
The remote end steps are:
-
If no FedCM dialog is currently open, return a WebDriver error with error code no such alert.
-
Let data be a dictionary with an object with properties as follows:
-
title
set to the title of the open dialog -
subtitle
set to the subtitle of the open dialog, if there is one
-
-
Return success with data data.
5.7. Get dialog type
HTTP Method | URI Template |
---|---|
GET | /session/{session id}/fedcm/getdialogtype
|
The remote end steps are:
-
If no FedCM dialog is currently open, return a WebDriver error with error code no such alert.
-
Let type be a string that is "
AutoReauthn
" if the user is being auto-reauthenticated, or "AccountChooser
" if the dialog is an account chooser, or "ConfirmIdpLogin
" if the dialog is a confirm IDP login dialog. -
Return success with data type.
5.8. Set delay enabled
HTTP Method | URI Template |
---|---|
POST | /session/{session id}/fedcm/ setdelayenabled
|
The remote end steps are:
-
If parameters is not a JSON Object, return a WebDriver error with error code invalid argument.
-
Let enabled be the result of getting a property named
"enabled"
from parameters. -
If enabled is
undefined
or is not a boolean, return a WebDriver error with error code invalid argument. -
If enabled is false, disables the promise rejection delay; otherwise, re-enables it.
-
Return success with data
null
.
5.9. Reset cooldown
HTTP Method | URI Template |
---|---|
POST | /session/{session id}/fedcm/resetcooldown
|
The remote end steps are:
-
If the user agent uses a cooldown delay, which disables the API for an amount of time after the user dismissed the dialog, then this command resets that cooldown such that the next FedCM call can succeed again.
-
Return success with data
null
.
6. Security
This section provides a few of the security considerations for the FedCM API. Note that there is a separate section for § 7 Privacy considerations.
6.1. Content Security Policy
The first fetches triggered by the FedCM API are the manifest list, which is public, and the config file. Imagine a malicious script included by (and running as) the RP attempting to execute the FedCM API calls to a malicious IDP, one which is not trusted by the RP. If the call is successful, this would introduce browser UI on the RP with sign in options into a malicious IDP. This maliciousIDP could then attempt to trick the user. The protection against this attack is the Content Security Policy Level 3 check, which would fail because the origin of the manifest of the malicious IDP would not be an origin included in the allowlist specified by the Content Security Policy Level 3 of the RP, hence preventing the undesired FedCM UI from being shown. Since any subsequent fetches are same origin with respect to the config file or at least dependent on the contents of the config file, they do not require additional checks.
The non-same-origin fetches include, for example, the brand icon. The user agent does not perform a Content Security Policy Level 3 check on these because they are directly specified from the manifest. In addition, the rendering of this image is performed by the user agent, and as such this image cannot affect the RP site nor can they be inspected by the RP in any way.
6.2. Sec-Fetch-Dest Header
The FedCM API introduces several non-static endpoints on the IDP, so these need to be protected
from XSS attacks. In order to do so, the FedCM API introduces a new value for the Sec-Fetch-Dest header, a forbidden request-header. The requests initiated by the FedCM API
have a webidentity
value for this header. The value cannot be set by random websites, so the IDP can be confident that the request was originated by the FedCM browser rather than sent by a
websites trying to run an XSS attack. An IDP needs to check for this header’s value in the
credentialed requests it receives, which ensures that the request was initiated by the user agent,
based on the FedCM API. A malicious actor cannot spam FedCM API calls, so this is sufficient
protection for the new IDP endpoints.
6.3. CORS Header
The FedCM API allows the response from the identity assertion endpoint to be shared to the RP. Because of this, we impose the requirement that the IDP explicitly consents to this sharing taking place by using the "cors" mode when fetching this endpoint. This also helps with servers that may accidentally ignore the Sec-Fetch-Dest: they cannot ignore CORS, as without it the fetch will fail.
6.4. Browser Surface Impersonation
The FedCM API introduces new (trusted) user agent UI, and the user agent may choose to show the UI entirely on top of the page’s contents, if anything because the page was the one responsible for this UI. This introduces a potential concern of a malicious site to try to replicate the FedCM UI, gain the user’s trust that the user is interacting with a trusted browser surface, and gather information from the user that they would only give to the browser rather than the site (e.g. usernames/passwords of another site). This would be hard to achieve because the FedCM UI uses metadata about the user accounts of the IDP, which the malicious website doesn’t have access to. If this is a malicious site, it would not know the user accounts unless the user is already compromised. However, the site could have some guess of the user identity, so the browser is encouraged to provide UI that is hard to replicate and that clearly presents the domains of the parties involved in the website’s FedCM call. Overall, an attacker trying to impersonate the browser using exclusively UI that is accessible to the content area (e.g. iframes) to attempt to retrieve sensitive information from the user would be noticeably different from the FedCM UI. Finally, because the FedCM UI can only be queried from the top-level frame (or potentially from an iframe with explicit permission from the top-level frame), the priviledged UI surface is only shown when the top-level frame wants it so. A sneaky iframe cannot force the FedCM UI to occlude important content from the main page.
7. Privacy
This section is intended to provide a comprehensive overview of the privacy risks associated with federated identity on the web for the purpose of measuring the privacy risks and benefits of proposed browser intermediation designs.
7.1. Principals
This section describes the four principals that would participate in an invocation of the API and expectations around their behavior.
-
The user agent implements § 2 The Browser API and controls the execution contexts for the RP and IDP content. The user agent is assumed to be trusted by the user, and transitively trusted by the RP and IDP.
-
RPs are websites that invoke the FedCM API for the purpose of authenticating a user to their account or for requesting information about that user. Since any site can invoke the API, RPs cannot necessarily be trusted to limit the user information it collects or use that information in an acceptable way.
-
IDPs are third-party websites that are the target of a FedCM call to attempt to fetch a token. Usually,the IDP has a higher level of trust than the RP since it already has the user’s personal information, but it is possible that the IDP might use the user’s information in non-approved ways. In addition, it is possible that the IDP specified in the API call may not be an IDP the user knows about. In this case, it likely does not have personal user information in advance.
-
A tracker is a third-party website that is not an IDP but could abuse the FedCM API exclusively for the purpose of tracking a user as they visit various websites. A tracker may be injected by the RP with or without their knowledge (e.g. injected into one of the various script tags that the RP embeds that is loaded dynamically), but they usually do not modify the UI of the website, so that it is harder to detect the tracking. A tracker that successfully adds tracking scripts for users in various websites may then use this information for various purposes, such as selling the information about the user. It should not be possible for trackers to use the FedCM API to track users across the web.
Based on the above, the privacy discussion makes the following assumptions:
-
It is not acceptable for an RP, IDP, or tracker to learn that a specific user visited a specific site, without any permission granted by the user. That is, the user agent needs to hide the knowledge that a specific user identity visited a specific site from the RP, IDP, and trackers. It may share this knowledge with the RP and IDP once the user grants permission. In particular, the RP should not know the user identity and the IDP should not know the site that the user has visited before the FedCM flow gathers the user’s permission to do so.
-
It is the user agent's responsibility to determine when the user has granted permission for the IDP to communicate with the RP in order to provide identification for the user.
-
Once the user agent has determined that the user has granted permission to provide their account information to the RP, it is ok for the IDP and for the RP to learn information about that specific user’s account, as required to provide identification. The RP should not learn about about any other user accounts.
7.2. Network requests
This specification ensures that the FedCM fetches are all same-origin with respect to the provider specified by the RP. The reason for this is because fetches with cookies would use the cookies from the origin specified, so allowing arbitrary origins would introduce confusion and potential privacy issues with regards to which cookies are shared and with whom within the FedCM flow. The easiest way to ensure that all of these fetches remain same-origin is by disabling redirects and checking the origin of the fetched URLs.
-
The config file fetch can’t be used to track users because it is performed without cookies,
client_id
, or referrer. Thus, anyone could perform this fetch, and the information contained therein is considered public. -
The accounts endpoint fetch can’t be used to track users because it is performed with cookies from the IDP but, importantly, without the
client_id
or referrer. This in theory is a new power that the RP gains that it would not have otherwise. Preventing too many of these fetches may be important, but IDPs are already expected to protect against DoS attacks. In addition, the user agent should only allow one FedCM flow per page at any given moment, immediately rejecting any attempts to start another one. Since a FedCM flow can only be terminated when the user interacts or after a long timer, the number of fetches performed is not a concern. The IDP does learn a lot about the user from this fetch, but this is discussed in detail below. -
The client metadata endpoint fetch can’t be used to track users too because it is performed without cookies from the IDP, albeit with a
client_id
and a referrer. This allows the IDP to communicate the relevant Privacy Policy and Terms of Service to the user agent, in case they need to be displayed. Again, besides possible timing attacks described here, the RP gains nothing from this fetch, and the RP could already perform this fetch if it wanted to since it involves no cookies from the IDP. -
By design, the token fetch exposes the user at the website to the IDP: it is peformed with cookies,
client_id
, and referrer. Because of that, it is gated on the user interacting with the user agent UI, and enables the IDP to communicate to the RP the information required to perform a federated signin/signup. It is not possible for the RP or the IDP to force the token fetch to happen without user permission, as the user agent cannot be spoofed or otherwise tricked. -
The disconnect endpoint may only be fetched after the user has successfully gone through the FedCM flow at least once in the RP. It sends a credentialed request to the IDP, so it is important that the user agent does not allow unlimited requests of such type, even after the user has used FedCM once. For this reason, any time that disconnection sends a credentialed request, at least one account is removed from the connected accounts set, thus ensuring that this endpoint does not introduce a way for the RP to send requests to the IDP containing the IDP cookies forever.
7.3. Attack Scenarios
This section describes the scenarios in which various agents might attempt to gain user information. It considers the possibilities when:
For the purposes of this section, a principal is considered to be participating in the collection of information if it directly or indirectly performs actions with the aim of realizing one of the above threats.
Note: An example of indirect collusion would be an RP importing a script supplied by an IDP where the IDP intends to track users.
For the purpose of discussion, this document assumes that third-party cookies are disabled by default and are no longer effective for use in tracking mechanisms, and also some form of mitigations are implemented against ‘bounce tracking’ using link decoration or postMessage. Most of these scenarios consider how user tracking might happen without them. See also Pervasive Monitoring Is an Attack.
7.3.1. Manifest Fingerprinting
Suppose that the FedCM API did not have a two-tier manifest (see the create an IdentityCredential algorithm), and instead directly had a single manifest. This would introduce the following fingerprinting attack:
// The following will fetch the manifest JSON file, which will know the origin of the RP :( const cred= await navigator. credentials. get({ identity: { providers: [{ configURL: \`https://idp.example/ ${ window. location. href} \` }] } });
NOTE: You can read more about the attack described here.
Here, the RP includes identifies itself when fetching the manifest from the IDP. This coupled with the credentialed fetches that the FedCM API performs would enable the IDP to easily track the website that the user is visiting, without requiring any permission from the user. Our mitigation to this problem is to use the § 3.1 The Well-Known File file. The existence of a file at the root of the IDP's domain is enforced to ensure that the file name does not introduce fingerprints about the RP being visited.
The whole manifest could be in this location, but instead it only points to the real manifest from there. This allows the flexibility in the future to allow a small constant number of manifests, should an IDP require this in the future, instead of just a single one. It also helps the IDP's implementation because they any changes to the manifest are more likely to be performed on a file located anywhere, as opposed to the root of the domain, which may have more constraints in terms of ease of update.
7.3.2. Timing Attacks
In the timing attack, the RP and IDP collude to allow the IDP to compute the (RP's origin, IDP's user identity) pair without the user’s permission. This attack is not deterministic: there is room for statistical error because it requires stitching together two separate pieces of information to track the user. However, it is important to mitigate this attack and ensure that it’s economically impractical to perform. In this attack, it is assumed that network requests do not have large fingerprinting vectors (e.g. IP addresses). These vary by user agent and are hard to eliminate entirely, but in general user agents are expected to address these over time. These bits of information tied to the network requests make the timing attack easier, making it more important to address.
Note: this attack is described and discussed here.
The attack is as follows:
-
The RP logs the time at which it invokes the API, time A and sends it to the IDP to learn itself by marking the time in which it receives the fetch for the RP's client metadata. Time A is tied to the site.
-
A credentialed request is sent to the IDP that does not explicitly identify the RP, but it is sent around a time that is close enough to the request above. The IDP notes the time in which this request has arrived, time B. Time B is tied to the user identity.
-
The IDP correlates time A and time B to find the (site, user identity) pair with high probability. Note that fingerprinting can make the correlation more accurate.
Note that this kind of correlation is already possible without FedCM by using simple cross-origin top-level navigations, but using FedCM for this purpose would worsen the problem if it improved timing resolution or if it was less visible to users (e.g. the IDP could return empty accounts to the user agent to deliberately make no browser UI to be triggered, and hence make this attack invisible to the user).
The user agent should mitigate this attack to protect users, in an interoperable way.
7.3.3. IDP Intrusion
From Target Privacy Threat Model § hl-intrusion
Privacy harms don’t always come from a site learning things.
From RFC6973: Intrusion
Intrusion consists of invasive acts that disturb or interrupt one’s life or activities. Intrusion can thwart individuals' desires to be left alone, sap their time or attention, or interrupt their activities.
In the context of federation, intrusion happens when an RP and an IDP are colluding to invasively and aggressively recommend the user to login disproportionally to the their intent. Much like unsolicited notifications, an RP can collude with an IDP to aggressively log users in.
The user agent can mitigate this by mediating the user controls and offering them proportionally to the intent of the user or the privacy risks involved. For example, a user agent can choose to show a loud / disruptive modal mediated dialog when it has enough confidence of the user’s intent or show a quiet / conservative UI hint when it doesn’t.
A user agent could also choose to control disruption of the user’s experience based on the risks involved. For example, when a directed identifier is being exchanged it can be more confident of the unintended consequeces and offer a more aggressive user experience, whereas when global identifiers are exchanged a more conservative user experience.
7.3.4. Cross-Site Correlation
This attack happens when multiple RPs collude to use their user’s data to correlate them and build a richer profile. When a user willingly provides their full name, email address, phone number, etc, to multiple relying parties, those relying parties can collaborate to build a profile of that user and their activity across collaborating sites. Sometimes this is referred to as joining since it amounts to a join of user records between the account databases of multiple RPs. This correlation and profile-building is outside the user’s control and entirely out of the user agent’s or IDP’s view.