From e2f48cc6eb6577a429867430e17c00cadab61c8e Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Tue, 14 Feb 2023 15:24:33 -0500 Subject: [PATCH 01/43] Add the IDP sign-in status API to the spec Explainer: https://github.com/fedidcg/FedCM/blob/main/proposals/idp-sign-in-status-api.md --- spec/index.bs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/spec/index.bs b/spec/index.bs index e27d516eb..1eac6d19d 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -301,6 +301,30 @@ value (which is used when a resource loaded as a third-party, not first-party). for an [=IDP=] to adopt the FedCM API without introducing security issues on the API, since the [=RP=] cannot inspect the results from the fetches in any way. + +## IDP sign-in status ## {#browser-api-idp-sign-in-status} + + +Each [=user agent=] keeps a global, persistent IDP sign-in status +map, an initially empty [=map=]. The [=map/keys=] in this map are +[=/origin=] (of IDPs), and the [=map/values=] are enums that can be one of +"unknown", "signed-in", and "signed-out". + +The user agent checks all page and subresource loads for an HTTP response +header named `IdP-SignIn-Status` containing [[RFC9110#parameter|Parameter]]s. +If that header exists and the first parameter has a name of `action`, +the user agent must process it as follows: + +* If this is a subresource request, and the subresource does not have the + same [=/origin] as the toplevel page, ignore the header. +* Otherwise: + * If the parameter value is `signin`, add (or replace) an entry in the + [=IDP sign-in status map=] with the key being the origin of the resource + and the value being "signed-in" + * If the parameter value is `signout-all`, add (or replace) an entry in the + [=IDP sign-in status map=] with the key being the origin of the resource + and the value being "signed-out" + ## The State Machine ## {#browser-api-state-machine} @@ -490,11 +514,28 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}} or failure. 1. Assert: These steps are running [=in parallel=]. + 1. Let |signinStatus| be the value of the entry in [=IDP sign-in status map=] + with the key being the origin of |provider|'s configURL. If there is + no such entry, set it to a user-agent specific default (either "unknown" or + "signed-out"). + 1. If |signinStatus| is "signed-out", return failure. 1. Let |config| be the result of running [=fetch the config file=] with |provider| and |globalObject|. 1. If |config| is failure, return failure. 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, and |globalObject|. + 1. If the fetch failed, or the size of |accountsList| is 0: + 1. Add (or replace) an entry in the [=IDP sign-in status map=] with the + key being the origin of the configURL and the value being "signed-out". + 1. If |signinStatus| is "signed-in", show a dialog to the user and return + failure. + + Note: It is recommended that this dialog provides a "sign in" button + allowing the user to sign in to the IDP using + {{IdentityProviderAPIConfig/signin_url}}. + 1. If |signinStatus| is "unknown", add (or replace) an entry in the [=IDP + sign-in status map=] with the key being the origin of the configURL and + the value being "signed-out". 1. For each |account| in |accountsList|: 1. If |account|["{{IdentityProviderAccount/picture}}"] is present, [=fetch the account picture=] with |account| and |globalObject|. @@ -675,6 +716,7 @@ dictionary IdentityProviderAPIConfig { required USVString accounts_endpoint; required USVString client_metadata_endpoint; required USVString id_assertion_endpoint; + USVString signin_url; IdentityProviderBranding branding; }; From 830496840224510c0141a25aaf284c063facac37 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 15 Feb 2023 14:08:21 -0500 Subject: [PATCH 02/43] Address comments --- spec/index.bs | 59 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 1eac6d19d..080a38cfe 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -302,28 +302,36 @@ for an [=IDP=] to adopt the FedCM API without introducing security issues on the [=RP=] cannot inspect the results from the fetches in any way. -## IDP sign-in status ## {#browser-api-idp-sign-in-status} +## IDP Sign-in Status ## {#browser-api-idp-sign-in-status} -Each [=user agent=] keeps a global, persistent IDP sign-in status +Each [=user agent=] keeps a global, persistent IDP Sign-in Status map, an initially empty [=map=]. The [=map/keys=] in this map are [=/origin=] (of IDPs), and the [=map/values=] are enums that can be one of -"unknown", "signed-in", and "signed-out". +"unknown", "signed-in", +and "signed-out" The user agent checks all page and subresource loads for an HTTP response -header named `IdP-SignIn-Status` containing [[RFC9110#parameter|Parameter]]s. +[[RFC9110#header.fields|header]] named `IdP-SignIn-Status`, whose value +is parsed at HTTP [[RFC9110#parameter|Parameter]]s. If that header exists and the first parameter has a name of `action`, the user agent must process it as follows: -* If this is a subresource request, and the subresource does not have the +* If this is a subresource request, and the response does not have the same [=/origin] as the toplevel page, ignore the header. * Otherwise: - * If the parameter value is `signin`, add (or replace) an entry in the - [=IDP sign-in status map=] with the key being the origin of the resource - and the value being "signed-in" - * If the parameter value is `signout-all`, add (or replace) an entry in the - [=IDP sign-in status map=] with the key being the origin of the resource - and the value being "signed-out" + * If the parameter value is `signin`, [=map/set=] an entry in the + [=IDP Sign-in Status map=] with the key being the origin of the resource + and the value being [=signed-in=] + * If the parameter value is `signout-all`, [=map/set=] an entry in the + [=IDP Sign-in Status map=] with the key being the origin of the resource + and the value being [=signed-out=] + +Issue: Should the header checking be integrated into the fetch spec instead, + since it affects all resources? + +User agents must also clear the [=IDP Sign-in Status map=] when the user clears +cookies or stored site data. ## The State Machine ## {#browser-api-state-machine} @@ -514,28 +522,39 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. This returns an {{IdentityCredential}} or failure. 1. Assert: These steps are running [=in parallel=]. - 1. Let |signinStatus| be the value of the entry in [=IDP sign-in status map=] + 1. Let |signinStatus| be the value of the entry in [=IDP Sign-in Status map=] with the key being the origin of |provider|'s configURL. If there is - no such entry, set it to a user-agent specific default (either "unknown" or - "signed-out"). - 1. If |signinStatus| is "signed-out", return failure. + no such entry, set it to a user-agent specific default (either [=unknown=] or + [=signed-out=]). + 1. If |signinStatus| is [=signed-out=], return failure. 1. Let |config| be the result of running [=fetch the config file=] with |provider| and |globalObject|. 1. If |config| is failure, return failure. 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, and |globalObject|. 1. If the fetch failed, or the size of |accountsList| is 0: - 1. Add (or replace) an entry in the [=IDP sign-in status map=] with the - key being the origin of the configURL and the value being "signed-out". - 1. If |signinStatus| is "signed-in", show a dialog to the user and return + 1. [=map/set|Set=] an entry in the [=IDP Sign-in Status map=] with the + key being the origin of the configURL and the value being [=signed-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. 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. + 1. If |signinStatus| is [=signed-in=], show a dialog to the user and return failure. Note: It is recommended that this dialog provides a "sign in" button allowing the user to sign in to the IDP using {{IdentityProviderAPIConfig/signin_url}}. - 1. If |signinStatus| is "unknown", add (or replace) an entry in the [=IDP + + 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. + 1. If |signinStatus| is [=unknown=], [=map/set=] an entry in the [=IDP sign-in status map=] with the key being the origin of the configURL and - the value being "signed-out". + the value being [=signed-in=]. 1. For each |account| in |accountsList|: 1. If |account|["{{IdentityProviderAccount/picture}}"] is present, [=fetch the account picture=] with |account| and |globalObject|. From 465c717475dd8b234d44154e7717b25c4c35cfff Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 15 Feb 2023 15:18:04 -0500 Subject: [PATCH 03/43] Add the JavaScript API --- spec/index.bs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/index.bs b/spec/index.bs index 080a38cfe..f420db613 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -333,6 +333,22 @@ Issue: Should the header checking be integrated into the fetch spec instead, User agents must also clear the [=IDP Sign-in Status map=] when the user clears cookies or stored site data. +IDPs can also use a JavaScript API to update the stored sign-in status: + +
+  [Exposed=Window, SecureContext]
+  interface IdentityProvider {
+    static void recordSignIn();
+    static void recordSignOut();
+  };
+
+ +When {{IdentityProvider/recordSignIn}} or {{IdentityProvider/recordSignOut}} is +called, the user agent [=map/set|sets=] the entry in the [=IDP Sign-in Status +Map=] with the [=map/key=] being [=this=]'s [=relevant global object=]'s +[=associated document=]'s [=/origin=] and the value being [=signed-in=] (for +`recordSignIn`) or [=signed-out=] (for `recordSignOut`). + ## The State Machine ## {#browser-api-state-machine} From 896e95d873c662c813c1079bfdf6a452d40a0118 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 15 Feb 2023 15:23:10 -0500 Subject: [PATCH 04/43] void->undefined and add an Issue comment regarding Promise --- spec/index.bs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index f420db613..ee3d80e53 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -338,11 +338,14 @@ IDPs can also use a JavaScript API to update the stored sign-in status:
   [Exposed=Window, SecureContext]
   interface IdentityProvider {
-    static void recordSignIn();
-    static void recordSignOut();
+    static undefined recordSignIn();
+    static undefined recordSignOut();
   };
 
+Issue: Should the functions return Promise, so the caller can know + when the call is finished? + When {{IdentityProvider/recordSignIn}} or {{IdentityProvider/recordSignOut}} is called, the user agent [=map/set|sets=] the entry in the [=IDP Sign-in Status Map=] with the [=map/key=] being [=this=]'s [=relevant global object=]'s From 07eb4070582ab760c9a361bfc0f0d64f76da4acf Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 15 Feb 2023 15:25:45 -0500 Subject: [PATCH 05/43] Slightly more direct way to get the origin --- spec/index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index ee3d80e53..84bfd4f46 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -348,8 +348,8 @@ Issue: Should the functions return Promise, so the caller can know When {{IdentityProvider/recordSignIn}} or {{IdentityProvider/recordSignOut}} is called, the user agent [=map/set|sets=] the entry in the [=IDP Sign-in Status -Map=] with the [=map/key=] being [=this=]'s [=relevant global object=]'s -[=associated document=]'s [=/origin=] and the value being [=signed-in=] (for +Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s +[=environment settings object/origin=] and the value being [=signed-in=] (for `recordSignIn`) or [=signed-out=] (for `recordSignOut`). From 8948f997c5548845cd49f12fea0fb740b7d505f4 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 15 Feb 2023 15:37:08 -0500 Subject: [PATCH 06/43] Add a multi-IDP note and clarify a signin note --- spec/index.bs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 84bfd4f46..cd022151f 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -546,6 +546,9 @@ failure. no such entry, set it to a user-agent specific default (either [=unknown=] or [=signed-out=]). 1. If |signinStatus| is [=signed-out=], return failure. + Issue: Should the user agent instead show UI to let the user sign + in to the IDP? This could be especially useful in the multi-IDP + case. 1. Let |config| be the result of running [=fetch the config file=] with |provider| and |globalObject|. 1. If |config| is failure, return failure. @@ -564,8 +567,10 @@ failure. 1. If |signinStatus| is [=signed-in=], show a dialog to the user and return failure. - Note: It is recommended that this dialog provides a "sign in" button - allowing the user to sign in to the IDP using + Note: Since this situation happens when the browser expects the user + to be signed in, but the accounts fetch indicated that the user + is signed out, it is recommended that this dialog provides a + "sign in" button allowing the user to sign in to the IDP using {{IdentityProviderAPIConfig/signin_url}}. Note: This dialog ensures that silent tracking of the user is From f19c44542c4a725bce1504bc40c6fd759cafd4c0 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Thu, 16 Feb 2023 16:23:51 -0500 Subject: [PATCH 07/43] Elaborate on state clearing --- spec/index.bs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index cd022151f..c8fb56257 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -312,8 +312,9 @@ map
, an initially empty [=map=]. The [=map/keys=] in this map are and "signed-out" The user agent checks all page and subresource loads for an HTTP response -[[RFC9110#header.fields|header]] named `IdP-SignIn-Status`, whose value -is parsed at HTTP [[RFC9110#parameter|Parameter]]s. +[[RFC9110#header.fields|header]] named +IdP-SignIn-Status, whose value is parsed at HTTP +[[RFC9110#parameter|Parameter]]s. If that header exists and the first parameter has a name of `action`, the user agent must process it as follows: @@ -330,8 +331,26 @@ the user agent must process it as follows: Issue: Should the header checking be integrated into the fetch spec instead, since it affects all resources? -User agents must also clear the [=IDP Sign-in Status map=] when the user clears -cookies or stored site data. +User agents must also clear the [=IDP Sign-in Status map=] data when: + : the user clears all cookies or site settings data + :: The user agent must clear the entire map + : the user clears cookies or site data for a specific origin + :: The user agent must remote all entries that would be affected + by the deleted cookies. + + Note: For example, domain cookies may affect subdomains of + the deleted origin. + : if the user agent allows deleting individual cookies + :: the behavior is user agent-defined. + + Note: The user agent may want to reset the state to undefined, + since is impossible to know whether this cookie affects + authorization state. + +Note: Website-initiated cookie changes should not affect this map. When + IDP sign-in state changes, it should send an explicit + [=IDP-SignIn-Status=]. + RP state should not affect this map since it only reflects IDP state. IDPs can also use a JavaScript API to update the stored sign-in status: From 090262d8400a5367b856a8b823898ff8882f83c5 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:04:41 -0400 Subject: [PATCH 08/43] Fix bikeshed syntax errors It seems newer bikeshed versions show this error: LINE 681:91: Missing attribute value. Fix by using instead of . --- spec/index.bs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index a734e5a3e..c3c2ee3df 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -678,7 +678,7 @@ or failure. [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. Let |config|, |configInWellKnown| both be null. - 1. [=Fetch request=] with |wellKnownRequest| and |globalObject|, and with processResponseConsumeBody + 1. [=Fetch request=] with |wellKnownRequest| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response |response| and |responseBody|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response| and |responseBody|. @@ -725,7 +725,7 @@ or failure. with [=request/mode=] set to "user-agent-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details. - 1. [=Fetch request=] with |configRequest| and |globalObject|, and with processResponseConsumeBody + 1. [=Fetch request=] with |configRequest| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response |response| and |responseBody|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response| and |responseBody|. @@ -819,7 +819,7 @@ To fetch the accounts list given an {{IdentityProviderAPIConfig}} |co [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. Let |accountsList| be null. - 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody + 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response |response| and |responseBody|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response| and |responseBody|. @@ -880,7 +880,7 @@ To fetch the account picture given an {{IdentityProviderAccount}} |ac with [=request/mode=] set to "user-agent-no-cors". See the relevant [pull request](https://github.com/whatwg/fetch/pull/1533) for details. - 1. [=Fetch request=] with |pictureRequest| and |globalObject|, and with processResponseConsumeBody + 1. [=Fetch request=] with |pictureRequest| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response and a |responseBody|: 1. If |responseBody| is null or failure, the user agent may choose an arbitrary placeholder image and associate it with the |account|. @@ -942,7 +942,7 @@ To fetch an identity assertion given a {{USVString}} [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. Let |credential| be null. - 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody + 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response |response| and |responseBody|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response| and |responseBody|. @@ -1041,7 +1041,7 @@ an {{IdentityProviderConfig}} |provider|, run the following steps. This returns [pull request](https://github.com/whatwg/fetch/pull/1533) for details. 1. Let |metadata| be null. - 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody + 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response |response| and |responseBody|: 1. Let |json| be the result of [=extract the JSON fetch response=] from |response| and |responseBody|. From 0c154cb02f9b47c9404fc7e13e0783b89de2325b Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:36:34 -0400 Subject: [PATCH 09/43] define interaction with clear-site-data --- spec/index.bs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/index.bs b/spec/index.bs index 4779bc5aa..3831e7338 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -326,7 +326,7 @@ and "signed-out" The user agent checks all page and subresource loads for an HTTP response [=header=] named IdP-SignIn-Status, whose value is -parsed as HTTP [[RFC9110#parameter|Parameter]]s. +parsed as HTTP [[RFC9110#section-5.6.6|Parameter]]s. If that header exists and the first parameter has a name of `action`, the user agent must process it as follows: @@ -383,6 +383,13 @@ Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s [=environment settings object/origin=] and the value being [=signed-in=] (for `recordSignIn`) or [=signed-out=] (for `recordSignOut`). +### Interaction with `Clear-Site-Data` + +When the user agent receives a Clear-Site-Data header with a +value of `"cookies"`, while [$clear cookies for origin|clearing cookies for +origin$] it must remove any entries in the [=IDP Sign-in Status Map=] where the +[=map/key=] is the input origin. + ## The connected accounts set ## {#browser-connected-accounts-set} From d932e3fdb18c4f66db111181eff454379abad156 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:51:16 -0400 Subject: [PATCH 10/43] better structure --- spec/index.bs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 3831e7338..a96ac9f49 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -364,24 +364,7 @@ Note: Website-initiated cookie changes should not affect this map. When [=IDP-SignIn-Status=]. RP state should not affect this map since it only reflects IDP state. -IDPs can also use a JavaScript API to update the stored sign-in status: - -
-  [Exposed=Window, SecureContext]
-  partial interface IdentityProvider {
-    static undefined recordSignIn();
-    static undefined recordSignOut();
-  };
-
- -Issue: Should the functions return Promise, so the caller can know - when the call is finished? - -When {{IdentityProvider/recordSignIn}} or {{IdentityProvider/recordSignOut}} is -called, the user agent [=map/set|sets=] the entry in the [=IDP Sign-in Status -Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s -[=environment settings object/origin=] and the value being [=signed-in=] (for -`recordSignIn`) or [=signed-out=] (for `recordSignOut`). +IDPs can also use a JavaScript API to update the stored sign-in, see {{IdentityProvider}}. ### Interaction with `Clear-Site-Data` @@ -1252,6 +1235,8 @@ This specification introduces the {{IdentityUserInfo}} dictionary as well as the }; [Exposed=Window, SecureContext] interface IdentityProvider { + static undefined recordSignIn(); + static undefined recordSignOut(); static Promise<sequence<IdentityUserInfo>> getUserInfo(IdentityProviderConfig config); }; @@ -1259,6 +1244,18 @@ This specification introduces the {{IdentityUserInfo}} dictionary as well as the Issue: [Decide](https://github.com/fedidcg/FedCM/issues/476) whether {{IdentityProvider}} is the correct location for the {{IdentityProvider/getUserInfo()}} method. +Issue: Should the recordSign{In,Out} functions return `Promise`, so the caller can know + when the call is finished? + +Issue: [Reconcile](https://github.com/speced/bikeshed/issues/2636) how these + record* functions relate to the isLoggedIn API. + +When {{IdentityProvider/recordSignIn}} or {{IdentityProvider/recordSignOut}} is +called, the user agent [=map/set|sets=] the entry in the [=IDP Sign-in Status +Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s +[=environment settings object/origin=] and the value being [=signed-in=] (for +`recordSignIn`) or [=signed-out=] (for `recordSignOut`). + 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=] [=list/contains=] From f128898cf8b178b16c0ae7e2fdd75c8db4e14825 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:52:38 -0400 Subject: [PATCH 11/43] less prescriptive about parameter location --- spec/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/index.bs b/spec/index.bs index a96ac9f49..40c12ca24 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -327,7 +327,7 @@ and "signed-out" The user agent checks all page and subresource loads for an HTTP response [=header=] named IdP-SignIn-Status, whose value is parsed as HTTP [[RFC9110#section-5.6.6|Parameter]]s. -If that header exists and the first parameter has a name of `action`, +If that header exists and any parameter has a name of `action`, the user agent must process it as follows: * If this is a subresource request, and the response does not have the From 71083c8014fc9275ceb62cff53f4958d699630db Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:53:56 -0400 Subject: [PATCH 12/43] typo --- spec/index.bs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 40c12ca24..99cb9f911 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -347,7 +347,7 @@ User agents must also clear the [=IDP Sign-in Status map=] data when: : the user clears all cookies or site settings data :: The user agent must clear the entire map : the user clears cookies or site data for a specific origin - :: The user agent must remote all entries that would be affected + :: The user agent must remove all entries that would be affected by the deleted cookies. Note: For example, domain cookies may affect subdomains of @@ -364,7 +364,8 @@ Note: Website-initiated cookie changes should not affect this map. When [=IDP-SignIn-Status=]. RP state should not affect this map since it only reflects IDP state. -IDPs can also use a JavaScript API to update the stored sign-in, see {{IdentityProvider}}. +IDPs can also use a JavaScript API to update the stored sign-in status, see +{{IdentityProvider}}. ### Interaction with `Clear-Site-Data` From 3fbe36525ff3d9efcf211c2e74c0c77aa2637be1 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:56:05 -0400 Subject: [PATCH 13/43] period --- spec/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/index.bs b/spec/index.bs index 99cb9f911..5b7fadda5 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -345,7 +345,7 @@ Issue: Should the header checking be integrated into the fetch spec instead, User agents must also clear the [=IDP Sign-in Status map=] data when: : the user clears all cookies or site settings data - :: The user agent must clear the entire map + :: The user agent must clear the entire map. : the user clears cookies or site data for a specific origin :: The user agent must remove all entries that would be affected by the deleted cookies. From 238fdf4e9bc96a905e90f351a313a73a5761d0b1 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 16:59:55 -0400 Subject: [PATCH 14/43] fix merge error --- spec/index.bs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 5b7fadda5..6829c7706 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -626,7 +626,7 @@ the exception thrown. 1. If |signinStatus| is [=signed-out=], return failure. Issue: Should the user agent instead show UI to let the user sign in to the IDP? This could be especially useful in the multi-IDP - case. + case. See https://github.com/fedidcg/FedCM/issues/442 for discussion. 1. Let |requiresUserMediation| be |provider|'s {{IdentityProviderConfig/configURL}}'s [=/origin=]'s [=requires user mediation=]. 1. Let |mediation| be |options|'s {{CredentialRequestOptions/mediation}}. @@ -662,9 +662,6 @@ the exception thrown. 1. If |signinStatus| is [=unknown=], [=map/set=] an entry in the [=IDP sign-in status map=] with the key being the origin of the configURL and the value being [=signed-in=]. - 1. For each |account| in |accountsList|: - 1. If |account|["{{IdentityProviderAccount/picture}}"] is present, - [=fetch the account picture=] with |account| and |globalObject|. 1. If |provider|'s {{IdentityProviderConfig/loginHint}} is not empty: 1. For every |account| in |accountList|, remove |account| from |accountList| if |account|'s {{IdentityProviderAccount/login_hints}} does not [=list/contain=] |provider|'s From 13ca4f71c87a88d183f62136c2306827e0fd5a8a Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Fri, 11 Aug 2023 17:02:28 -0400 Subject: [PATCH 15/43] elaborate on cookie deletion --- spec/index.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/index.bs b/spec/index.bs index 6829c7706..d040f038a 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -348,7 +348,8 @@ User agents must also clear the [=IDP Sign-in Status map=] data when: :: The user agent must clear the entire map. : the user clears cookies or site data for a specific origin :: The user agent must remove all entries that would be affected - by the deleted cookies. + 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. From 0c77ac984c5d5e62c25aa8411957943ee79c6248 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 23 Aug 2023 17:15:53 -0400 Subject: [PATCH 16/43] review comments --- spec/index.bs | 75 +++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index d040f038a..a95d5a22f 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -315,35 +315,39 @@ for an [=IDP=] to adopt the FedCM API. It doesn't introduce security issues on t [=RP=] cannot inspect the results from the fetches in any way. -## IDP Sign-in Status ## {#browser-api-idp-sign-in-status} +## The Sign-in Status API ## {#browser-api-sign-in-status} -Each [=user agent=] keeps a global, persistent IDP Sign-in Status +Each [=user agent=] keeps a global, persistent Sign-in Status map, an initially empty [=map=]. The [=map/keys=] in this map are [=/origin=] (of IDPs), and the [=map/values=] are enums that can be one of "unknown", "signed-in", and "signed-out" The user agent checks all page and subresource loads for an HTTP response -[=header=] named IdP-SignIn-Status, whose value is +[=header=] named SignIn-Status, whose value is parsed as HTTP [[RFC9110#section-5.6.6|Parameter]]s. -If that header exists and any parameter has a name of `action`, -the user agent must process it as follows: +If that header exists, there is a parameter with name `type` and value `idp`, +and any parameter has a name of `action`, the user agent must process it as +follows: +
* If this is a subresource request, and the response does not have the same [=/origin] as the toplevel page, ignore the header. * Otherwise: * If the parameter value is `signin`, [=map/set=] an entry in the - [=IDP Sign-in Status map=] with the key being the origin of the resource + [=Sign-in Status map=] with the key being the origin of the resource and the value being [=signed-in=] * If the parameter value is `signout-all`, [=map/set=] an entry in the - [=IDP Sign-in Status map=] with the key being the origin of the resource + [=Sign-in Status map=] with the key being the origin of the resource and the value being [=signed-out=] +
+ Issue: Should the header checking be integrated into the fetch spec instead, since it affects all resources? -User agents must also clear the [=IDP Sign-in Status map=] data when: +User agents must also clear the [=Sign-in Status map=] data when: : the user clears all cookies or site settings data :: The user agent must clear the entire map. : the user clears cookies or site data for a specific origin @@ -362,17 +366,38 @@ User agents must also clear the [=IDP Sign-in Status map=] data when: Note: Website-initiated cookie changes should not affect this map. When IDP sign-in state changes, it should send an explicit - [=IDP-SignIn-Status=]. + [=SignIn-Status=]. RP state should not affect this map since it only reflects IDP state. -IDPs can also use a JavaScript API to update the stored sign-in status, see -{{IdentityProvider}}. +IDPs can also use a JavaScript API to update the stored sign-in status: -### Interaction with `Clear-Site-Data` + +
+  dictionary SignInStatusOptions {
+    boolean idp;
+  };
+
+  partial interface Navigator {
+    static Promise<undefined> recordSignIn(optional SignInStatusOptions options);
+    static Promise<undefined> recordSignOut(optional SignInStatusOptions options);
+  };
+
+ +When {{Navigator/recordSignIn}} or {{Navigator/recordSignOut}} is +called: + * If no |options| dictionary is provided, or there is no |idp| member in the + dictionary, or the |idp| member is false, then the promise is rejected with + a {{TypeError}}. + * Otherwise, the user agent [=map/set|sets=] the entry in the [=Sign-in Status + Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s + [=environment settings object/origin=] and the value being [=signed-in=] (for + `recordSignIn`) or [=signed-out=] (for `recordSignOut`). + +### Interaction with `Clear-Site-Data` ### {#browser-clear-site-data} When the user agent receives a Clear-Site-Data header with a value of `"cookies"`, while [$clear cookies for origin|clearing cookies for -origin$] it must remove any entries in the [=IDP Sign-in Status Map=] where the +origin$] it must remove any entries in the [=Sign-in Status Map=] where the [=map/key=] is the input origin. @@ -620,7 +645,7 @@ To create an IdentityCredential given an {{IdentityProviderConfig}} or a pair (failure, bool), where the bool indicates whether to skip delaying the exception thrown. 1. Assert: These steps are running [=in parallel=]. - 1. Let |signinStatus| be the value of the entry in [=IDP Sign-in Status map=] + 1. Let |signinStatus| be the value of the entry in [=Sign-in Status map=] with the key being the origin of |provider|'s configURL. If there is no such entry, set it to a user-agent specific default (either [=unknown=] or [=signed-out=]). @@ -639,7 +664,7 @@ the exception thrown. 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, and |globalObject|. 1. If the fetch failed, or the size of |accountsList| is 0: - 1. [=map/set|Set=] an entry in the [=IDP Sign-in Status map=] with the + 1. [=map/set|Set=] an entry in the [=Sign-in Status map=] with the key being the origin of the configURL and the value being [=signed-out=]. A user agent may decide to skip this step if no credentials were sent to server. @@ -660,9 +685,9 @@ the exception thrown. 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. - 1. If |signinStatus| is [=unknown=], [=map/set=] an entry in the [=IDP - sign-in status map=] with the key being the origin of the configURL and - the value being [=signed-in=]. + 1. If |signinStatus| is [=unknown=], [=map/set=] an entry in the [=sign-in + status map=] with the key being the origin of the configURL and the value being + [=signed-in=]. 1. If |provider|'s {{IdentityProviderConfig/loginHint}} is not empty: 1. For every |account| in |accountList|, remove |account| from |accountList| if |account|'s {{IdentityProviderAccount/login_hints}} does not [=list/contain=] |provider|'s @@ -1234,8 +1259,6 @@ This specification introduces the {{IdentityUserInfo}} dictionary as well as the }; [Exposed=Window, SecureContext] interface IdentityProvider { - static undefined recordSignIn(); - static undefined recordSignOut(); static Promise<sequence<IdentityUserInfo>> getUserInfo(IdentityProviderConfig config); }; @@ -1243,18 +1266,6 @@ This specification introduces the {{IdentityUserInfo}} dictionary as well as the Issue: [Decide](https://github.com/fedidcg/FedCM/issues/476) whether {{IdentityProvider}} is the correct location for the {{IdentityProvider/getUserInfo()}} method. -Issue: Should the recordSign{In,Out} functions return `Promise`, so the caller can know - when the call is finished? - -Issue: [Reconcile](https://github.com/speced/bikeshed/issues/2636) how these - record* functions relate to the isLoggedIn API. - -When {{IdentityProvider/recordSignIn}} or {{IdentityProvider/recordSignOut}} is -called, the user agent [=map/set|sets=] the entry in the [=IDP Sign-in Status -Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s -[=environment settings object/origin=] and the value being [=signed-in=] (for -`recordSignIn`) or [=signed-out=] (for `recordSignOut`). - 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=] [=list/contains=] From afe7360adeb0fb7177083c2bed3b1f52c2d3fb29 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 23 Aug 2023 17:21:38 -0400 Subject: [PATCH 17/43] fix IDL syntax error --- spec/index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index a95d5a22f..b4159b211 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -378,15 +378,15 @@ IDPs can also use a JavaScript API to update the stored sign-in status: }; partial interface Navigator { - static Promise<undefined> recordSignIn(optional SignInStatusOptions options); - static Promise<undefined> recordSignOut(optional SignInStatusOptions options); + static Promise<undefined> recordSignIn(optional SignInStatusOptions options = {}); + static Promise<undefined> recordSignOut(optional SignInStatusOptions options = {}); }; When {{Navigator/recordSignIn}} or {{Navigator/recordSignOut}} is called: - * If no |options| dictionary is provided, or there is no |idp| member in the - dictionary, or the |idp| member is false, then the promise is rejected with + * If no |options| dictionary is provided, or there is no |idp| member inthe + |options|, or the |idp| member is false, then the promise is rejected with a {{TypeError}}. * Otherwise, the user agent [=map/set|sets=] the entry in the [=Sign-in Status Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s From ddb3f244fb4ef05d2f1ba2c9599a35ed474d3f45 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Wed, 23 Aug 2023 17:35:40 -0400 Subject: [PATCH 18/43] automation --- spec/index.bs | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index b4159b211..4877227b7 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -678,8 +678,9 @@ the exception thrown. Note: Since this situation happens when the browser expects the user to be signed in, but the accounts fetch indicated that the user - is signed out, it is recommended that this dialog provides a - "sign in" button allowing the user to sign in to the IDP using + is signed out, it is recommended that this dialog is a confirm + IDP signin dialog and provides a "sign in" button allowing + the user to sign in to the IDP using {{IdentityProviderAPIConfig/signin_url}}. Note: This dialog ensures that silent tracking of the user is @@ -1874,6 +1875,36 @@ The [=remote end steps=] are: 1. Return [=success=] with data `null`. +## Confirm IDP signin ## {#webdriver-confirmidpsignin} + +
+ + + + + + + + + + + + + +
HTTP MethodURI Template
POST`/session/{session id}/fedcm/confirm_idp_signin`
+
+ +The [=remote end steps=] are: + +1. If no FedCM dialog is currently open, or the dialog is not a [=confirm IDP + signin dialog=] return a [=error|WebDriver error=] with [=error code=] + [=no such alert=]. + +1. Act as if the user had clicked the "continue" button in the dialog and + initiate the signin flow. + +1. Return [=success=] with data `null`. + ## Account list ## {#webdriver-accountlist}
@@ -1985,7 +2016,8 @@ The [=remote end steps=] are: [=error code=] [=no such alert=]. 1. Let |type| be a string that is "`AutoReauthn`" if the user is being [=auto-reauthenticated=], - or "`AccountChooser`" otherwise. + or "`AccountChooser`" is the dialog is an account chooser, or "`ConfirmIdpSignin`" if the + dialog is a [=confirm IDP signin dialog=]. 1. Return [=success=] with data |type|. From 209813464318dd748240324bec9f8eaa60aaaf47 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Thu, 7 Sep 2023 15:33:23 -0400 Subject: [PATCH 19/43] fix most comments from the PR --- spec/index.bs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 4877227b7..1230f2bf9 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -333,7 +333,7 @@ follows:
* If this is a subresource request, and the response does not have the - same [=/origin] as the toplevel page, ignore the header. + same [=/origin=] as the toplevel page, ignore the header. * Otherwise: * If the parameter value is `signin`, [=map/set=] an entry in the [=Sign-in Status map=] with the key being the origin of the resource @@ -360,7 +360,7 @@ User agents must also clear the [=Sign-in Status map=] data when: : if the user agent allows deleting individual cookies :: the behavior is user agent-defined. - Note: The user agent may want to reset the state to undefined, + Note: The user agent may want to reset the state to [=unknown=], since is impossible to know whether this cookie affects authorization state. @@ -385,11 +385,11 @@ IDPs can also use a JavaScript API to update the stored sign-in status: When {{Navigator/recordSignIn}} or {{Navigator/recordSignOut}} is called: - * If no |options| dictionary is provided, or there is no |idp| member inthe + * If no |options| dictionary is provided, or there is no |idp| member in the |options|, or the |idp| member is false, then the promise is rejected with a {{TypeError}}. * Otherwise, the user agent [=map/set|sets=] the entry in the [=Sign-in Status - Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s + Map=] with the [=map/key=] being [=/this=]'s [=/relevant settings object=]'s [=environment settings object/origin=] and the value being [=signed-in=] (for `recordSignIn`) or [=signed-out=] (for `recordSignOut`). @@ -650,6 +650,7 @@ the exception thrown. no such entry, set it to a user-agent specific default (either [=unknown=] or [=signed-out=]). 1. If |signinStatus| is [=signed-out=], return failure. + Issue: Should the user agent instead show UI to let the user sign in to the IDP? This could be especially useful in the multi-IDP case. See https://github.com/fedidcg/FedCM/issues/442 for discussion. @@ -663,11 +664,11 @@ the exception thrown. 1. If |config| is failure, return (failure, false). 1. Let |accountsList| be the result of [=fetch the accounts list=] with |config|, |provider|, and |globalObject|. - 1. If the fetch failed, or the size of |accountsList| is 0: + 1. If |accountsList| is failure, or the size of |accountsList| is 0: 1. [=map/set|Set=] an entry in the [=Sign-in Status map=] with the - key being the origin of the configURL and the value being [=signed-out=]. - A user agent may decide to skip this step if no credentials were sent to - server. + key being the [=/origin=] of the {{IdentityProviderConfig/configURL}} + and the value being [=signed-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. In this situation, we do not know whether From 5b091a08eb8138a48643ad0048704ba671847851 Mon Sep 17 00:00:00 2001 From: Christian Biesinger Date: Thu, 7 Sep 2023 17:16:26 -0400 Subject: [PATCH 20/43] more editorial fixes --- spec/index.bs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 1230f2bf9..b5277b849 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -49,6 +49,7 @@ spec:html; type:dfn; for:environment settings object; text:global object spec:html; type:dfn; for:html-origin-def; text:origin spec:webidl; type:dfn; text:resolve spec:webdriver2; type:dfn; text:error +spec:fetch; type:dfn; for:/; text:response