>.
-
-For example:
-
-
-```json
-{
- "accounts_endpoint": "/accounts",
- "client_metadata_endpoint": "/metadata",
- "id_assertion_endpoint": "/assertion",
- "branding": {
- "background_color": "green",
- "color": "0xFFEEAA",
- "icons": [{
- "url": "https://idp.example/icon.ico",
- "size": 25
- }]
- }
-}
-```
-
-
-
-## Accounts List ## {#idp-api-accounts-endpoint}
-
-
-The accounts list endpoint provides the list of accounts the user has at the [=IDP=].
-
-The accounts list endpoint is fetched
-(a) **with** [=IDP=] cookies,
-(b) **with** the Sec-Fetch-Dest header set to `webidentity`,
-(c) **without** revealing the [=RP=] in the Origin or
- [[RFC9110#field.referer|Referer]] headers, and
-(d) **without** following [[RFC9110#field.location|HTTP redirects]].
-
-For example:
-
-
-```http
-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 IDL value|converted=] to an {{IdentityProviderAccountList}} without an exception.
-
-
-
-dictionary IdentityProviderAccount {
- required USVString id;
- required USVString name;
- required USVString email;
- USVString given_name;
- USVString picture;
- sequence approved_clients;
-};
-dictionary IdentityProviderAccountList {
- sequence accounts;
-};
-
-
-Every {{IdentityProviderAccount}} is expected to have members with the following semantics:
-
-
- : id
- :: The account unique identifier.
- : name
- :: The user's full name.
- : email
- :: The user's email address.
- : given_name
- :: The user's given name.
- : picture
- :: URL for the account's picture.
- : approved_clients
- :: A list of [=RP=]s (that gets matched against the requesting {{IdentityProviderConfig/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.
-
-
-For example:
-
-
-```json
-{
- "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"]
- }, {
- "id": "5678",
- "given_name": "Johnny",
- "name": "Johnny",
- "email": "johnny@idp.example",
- "picture": "https://idp.example/profile/456"
- "approved_clients": ["abc", "def", "ghi"]
- }]
-}
-```
-
-
-Issue: [Clarify](https://github.com/fedidcg/FedCM/issues/218) the IDP API response when the user is not signed in.
-
-
-## Client Metadata ## {#idp-api-client-id-metadata-endpoint}
-
-
-The client metadata endpoint provides metadata about [=RP=]s.
-
-The client medata endpoint is fetched
-(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 [[RFC9110#field.location|HTTP redirects]].
-
-The user agent also passes the **client_id**.
-
-For example:
-
-
-```http
-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 IDL value|converted=] to an {{IdentityProviderClientMetadata}} without an exception.
-
-
-dictionary IdentityProviderClientMetadata {
- USVString privacy_policy_url;
- USVString terms_of_service_url;
-};
-
-
-The {{IdentityProviderClientMetadata}} object's members have the following semantics:
-
-
- : privacy_policy_url
- :: A link to the [=RP=]'s Privacy Policy.
- : terms_of_service_url
- :: A link to the [=RP=]'s Terms of Service.
-
-
-For example:
-
-
-```json
-{
- "privacy_policy_url": "https://rp.example/clientmetadata/privacy_policy.html",
- "terms_of_service_url": "https://rp.example/clientmetadata/terms_of_service.html"
-}
-```
-
-
-
-## Identity Assertions ## {#idp-api-id-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
-
-(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 [[RFC9110#field.location|HTTP redirects]].
-
-It will also contain the following parameters in the request body `application/x-www-form-urlencoded`:
-
-
- : client_id
- :: The [=RP=]'s unique identifier from the [=IDP=]
- : 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 but
- not by the [=sign-in=] algorithm for returning users.
-
-
-For example:
-
-
-```http
-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
-```
-
-
-
-An [=IDP=] MUST check the
Origin header to ensure that a malicious [=RP=] does
-not receive an ID token corresponding to another [=RP=]. In other words, the [=IDP=] MUST check that
-the
Origin header value is represented by the
-{{IdentityProviderConfig/clientId}}. As the {{IdentityProviderConfig/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 IDL value|converted=] to an {{IdentityProviderToken}} without an exception.
-
-
-dictionary IdentityProviderToken {
- required USVString token;
-};
-
-
-Every {{IdentityProviderToken}} is expected to have members with the following semantics:
-
-
- : token
- :: The resulting token.
-
-
-The content of the {{IdentityProviderToken/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 {{IdentityProviderToken/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](https://github.com/fedidcg/FedCM/issues/314) 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](https://openid.net/specs/openid-connect-account-porting-1_0.html)).
-
-For example:
-
-
-```json
-{
- "token" : "eyJC...J9.eyJzdWTE2...MjM5MDIyfQ.SflV_adQssw....5c"
-}
-```
-
-
# The Browser API # {#browser-api}
@@ -1344,6 +907,442 @@ To sign-in the user with a given an [=AccountState=] |accountState|:
1. Change |accountState|'s {{AccountState/allows logout}} from false to true.
+
+# Identity Provider HTTP API # {#idp-api}
+
+
+This section is non-normative.
+
+The [=IDP=] proactively and cooperatively exposes itself as a comformant agent
+by exposing a series of HTTP endpoints:
+
+1. A [[#idp-api-manifest]] endpoint in an agreed upon location that points to
+1. An [[#idp-api-accounts-endpoint]] endpoint
+1. A [[#idp-api-client-id-metadata-endpoint]] endpoint
+1. An [[#idp-api-id-assertion-endpoint]] endpoint
+
+
+The [=IDP=] must also host a file at the ".well-known/web-identity" path of its [=registrable domain=] that has JSON contents that are convertable to an {{IdentityProviderWellKnown}} object.
+
+
+dictionary IdentityProviderWellKnown {
+ required sequence provider_urls;
+};
+
+
+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:
+
+
+
+
+## The Well-Known File ## {#idp-api-well-known}
+
+
+NOTE: The browser uses the well-known file to prevent the following attack described [here](https://github.com/fedidcg/FedCM/issues/230#issuecomment-1067029200).
+
+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:
+
+(a) **without** cookies,
+(b) **with** the Sec-Fetch-Dest header set to `webidentity`, and
+(c) **without** revealing the [=RP=] in the Origin or
+ [[RFC9110#field.referer|Referer]] headers.
+
+For example:
+
+
+```http
+GET /.well-known/web-identity HTTP/1.1
+Host: idp.example
+Accept: application/json
+Sec-Fetch-Dest: webidentity
+```
+
+
+The file is parsed expecting a [=Well-Known=] JSON object.
+
+The Well-Known JSON object has the following properties:
+
+
+ : provider_urls (required)
+ :: A list of URLs that points to valid [[#idp-api-manifest]]s.
+
+
+
+## Manifest ## {#idp-api-manifest}
+
+
+The config endpoint is an endpoint
+which serves as a discovery device to other endpoints provided by the
+[=IDP=].
+
+The config endpoint is fetched:
+
+(a) **without** cookies,
+(b) **with** the Sec-Fetch-Dest header set to `webidentity`,
+(c) **without** revealing the [=RP=] in the Origin or
+ [[RFC9110#field.referer|Referer]] headers, and
+(c) **without** following [[RFC9110#field.location|HTTP redirects]].
+
+For example:
+
+
+```http
+GET /config.json HTTP/1.1
+Host: idp.example
+Accept: application/json
+Sec-Fetch-Dest: webidentity
+```
+
+
+The response body must be a JSON object that can be [=converted to an IDL value|converted=] to an {{IdentityProviderAPIConfig}} without an exception.
+
+
+dictionary IdentityProviderIcon {
+ required USVString url;
+ unsigned long size;
+};
+
+dictionary IdentityProviderBranding {
+ USVString background_color;
+ USVString color;
+ sequence icons;
+};
+
+dictionary IdentityProviderAPIConfig {
+ required USVString accounts_endpoint;
+ required USVString client_metadata_endpoint;
+ required USVString id_assertion_endpoint;
+ IdentityProviderBranding branding;
+};
+
+
+The {{IdentityProviderAPIConfig}} object's members have the following semantics:
+
+
+ : accounts_endpoint
+ :: A URL that points to an HTTP API that complies with the [[#idp-api-accounts-endpoint]] API.
+ : client_metadata_endpoint
+ :: A URL that points to an HTTP API that complies with the [[#idp-api-client-id-metadata-endpoint]] API.
+ : id_assertion_endpoint
+ :: A URL that points to an HTTP API that complies with the [[#idp-api-id-assertion-endpoint]] API.
+ : branding
+ :: 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
+ :: Background [=color=] for [=IDP=]-branded widgets such as buttons.
+ : color
+ :: [=color=] for text on [=IDP=] branded widgets.
+ : icons
+ :: A list of {{IdentityProviderIcon}} objects.
+
+
+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
+ :: 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](https://www.w3.org/TR/appmanifest/#icon-masks) specification.
+ : size
+ :: 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 <> syntax, namely <>s, ''hsl()''s, ''rgb()''s and <>.
+
+For example:
+
+
+```json
+{
+ "accounts_endpoint": "/accounts",
+ "client_metadata_endpoint": "/metadata",
+ "id_assertion_endpoint": "/assertion",
+ "branding": {
+ "background_color": "green",
+ "color": "0xFFEEAA",
+ "icons": [{
+ "url": "https://idp.example/icon.ico",
+ "size": 25
+ }]
+ }
+}
+```
+
+
+
+## Accounts List ## {#idp-api-accounts-endpoint}
+
+
+The accounts list endpoint provides the list of accounts the user has at the [=IDP=].
+
+The accounts list endpoint is fetched
+(a) **with** [=IDP=] cookies,
+(b) **with** the Sec-Fetch-Dest header set to `webidentity`,
+(c) **without** revealing the [=RP=] in the Origin or
+ [[RFC9110#field.referer|Referer]] headers, and
+(d) **without** following [[RFC9110#field.location|HTTP redirects]].
+
+For example:
+
+
+```http
+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 IDL value|converted=] to an {{IdentityProviderAccountList}} without an exception.
+
+
+
+dictionary IdentityProviderAccount {
+ required USVString id;
+ required USVString name;
+ required USVString email;
+ USVString given_name;
+ USVString picture;
+ sequence approved_clients;
+};
+dictionary IdentityProviderAccountList {
+ sequence accounts;
+};
+
+
+Every {{IdentityProviderAccount}} is expected to have members with the following semantics:
+
+
+ : id
+ :: The account unique identifier.
+ : name
+ :: The user's full name.
+ : email
+ :: The user's email address.
+ : given_name
+ :: The user's given name.
+ : picture
+ :: URL for the account's picture.
+ : approved_clients
+ :: A list of [=RP=]s (that gets matched against the requesting {{IdentityProviderConfig/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.
+
+
+For example:
+
+
+```json
+{
+ "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"]
+ }, {
+ "id": "5678",
+ "given_name": "Johnny",
+ "name": "Johnny",
+ "email": "johnny@idp.example",
+ "picture": "https://idp.example/profile/456"
+ "approved_clients": ["abc", "def", "ghi"]
+ }]
+}
+```
+
+
+Issue: [Clarify](https://github.com/fedidcg/FedCM/issues/218) the IDP API response when the user is not signed in.
+
+
+## Client Metadata ## {#idp-api-client-id-metadata-endpoint}
+
+
+The client metadata endpoint provides metadata about [=RP=]s.
+
+The client medata endpoint is fetched
+(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 [[RFC9110#field.location|HTTP redirects]].
+
+The user agent also passes the **client_id**.
+
+For example:
+
+
+```http
+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 IDL value|converted=] to an {{IdentityProviderClientMetadata}} without an exception.
+
+
+dictionary IdentityProviderClientMetadata {
+ USVString privacy_policy_url;
+ USVString terms_of_service_url;
+};
+
+
+The {{IdentityProviderClientMetadata}} object's members have the following semantics:
+
+
+ : privacy_policy_url
+ :: A link to the [=RP=]'s Privacy Policy.
+ : terms_of_service_url
+ :: A link to the [=RP=]'s Terms of Service.
+
+
+For example:
+
+
+```json
+{
+ "privacy_policy_url": "https://rp.example/clientmetadata/privacy_policy.html",
+ "terms_of_service_url": "https://rp.example/clientmetadata/terms_of_service.html"
+}
+```
+
+
+
+## Identity Assertions ## {#idp-api-id-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
+
+(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 [[RFC9110#field.location|HTTP redirects]].
+
+It will also contain the following parameters in the request body `application/x-www-form-urlencoded`:
+
+
+ : client_id
+ :: The [=RP=]'s unique identifier from the [=IDP=]
+ : 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 but
+ not by the [=sign-in=] algorithm for returning users.
+
+
+For example:
+
+
+```http
+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
+```
+
+
+
+An [=IDP=] MUST check the
Origin header to ensure that a malicious [=RP=] does
+not receive an ID token corresponding to another [=RP=]. In other words, the [=IDP=] MUST check that
+the
Origin header value is represented by the
+{{IdentityProviderConfig/clientId}}. As the {{IdentityProviderConfig/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 IDL value|converted=] to an {{IdentityProviderToken}} without an exception.
+
+
+dictionary IdentityProviderToken {
+ required USVString token;
+};
+
+
+Every {{IdentityProviderToken}} is expected to have members with the following semantics:
+
+
+ : token
+ :: The resulting token.
+
+
+The content of the {{IdentityProviderToken/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 {{IdentityProviderToken/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](https://github.com/fedidcg/FedCM/issues/314) 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](https://openid.net/specs/openid-connect-account-porting-1_0.html)).
+
+For example:
+
+
+```json
+{
+ "token" : "eyJC...J9.eyJzdWTE2...MjM5MDIyfQ.SflV_adQssw....5c"
+}
+```
+
+
## Backwards Compatibility ## {#browser-api-backwards-compatibility}