Skip to content

Commit

Permalink
Replace the 60 second timeout with a random delay (#453)
Browse files Browse the repository at this point in the history
* Replace the 60 second timeout with a random delay

This is a better user experience and also gives user agents mores
flexibility for their UI. It also makes the spec match Chrome's current
implementation.

This change does not add a delay when the user closes the dialog
explicitly. This is not necessary because the timing is effectively
random and therefore indistinguishable from other failures that do
have this delay, and it allows RPs to fall back to different types
of authentication immediately in this case.

Closes #389

* pair

* review comments

* add note

* remove 60s
  • Loading branch information
cbiesinger authored May 9, 2023
1 parent 6ca279e commit c8609ec
Showing 1 changed file with 25 additions and 17 deletions.
42 changes: 25 additions & 17 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -482,20 +482,26 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu


Issue: Support choosing accounts from multiple [=IDP=]s, as described [here](https://github.com/fedidcg/FedCM/issues/319).
1. Run {{WindowOrWorkerGlobalScope/setTimeout()}} passing a [=task=] which throws a
{{NetworkError}}, after a timeout of 60 seconds.

Issue: Do not use {{WindowOrWorkerGlobalScope/setTimeout()}} directly, as that is not correct. See the relevant
[issue](https://github.com/fedidcg/FedCM/issues/389).

Note: the purpose of having a timer here is to avoid leaking the reason causing this
method to throw an error. If there was no such timer, the developer could easily infer
whether the user has an account with the [=IDP=] or not, or whether the user closed the UI without granting permission to share the [=IDP=] account information with the [=RP=].
1. Let |provider| be |options|["{{CredentialRequestOptions/identity}}"]["{{IdentityCredentialRequestOptions/providers}}"][0].
1. Let |credential| be the result of running [=create an IdentityCredential=] with |provider|,
|options|["{{CredentialRequestOptions/mediation}}"], and |globalObject|.
1. If |credential| is failure, throw a new "{{NetworkError}}" {{DOMException}}.
1. Return |credential|.
1. If |credential| is a pair:
1. Let |throwImmediately| be the value of the second element of the pair.
1. If |throwImmediately| is false, the user agent SHOULD wait a random
amount of time before the next step, unless it has 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 we resolved the promise 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, we specify
this delay. However, UAs may have different UI approaches here and prevent
it in a different way.
1. [=Queue a global task=] on the [=DOM manipulation task source=]
to throw a new "{{NetworkError}}" {{DOMException}}.
1. Otherwise, return |credential|.
</div>

<!-- ============================================================ -->
Expand All @@ -507,19 +513,21 @@ agent UI, and creates the {{IdentityCredential}} that is then returned to the [=

<div algorithm>
To <dfn>create an IdentityCredential</dfn> given an {{IdentityProviderConfig}}
|provider|, a {{CredentialRequestOptions/mediation}} |mediation|, and a |globalObject|, run the
following steps. This returns an {{IdentityCredential}} or failure.
|provider|, a {{CredentialRequestOptions/mediation}} |mediation|, 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.
1. Assert: These steps are running [=in parallel=].
1. Let |requiresUserMediation| be |provider|'s {{IdentityProviderConfig/configURL}}'s [=/origin=]'s
[=requires user mediation=].
1. If |requiresUserMediation| is true and |mediation| is
"{{CredentialMediationRequirement/silent}}", 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. 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 |accountsList| is failure, return failure.
1. If |accountsList| is failure, return (failure, false).
1. For each |acc| in |accountsList|:
1. If |acc|["{{IdentityProviderAccount/picture}}"] is present, [=fetch the account picture=]
with |acc| and |globalObject|.
Expand Down Expand Up @@ -554,7 +562,7 @@ following steps. This returns an {{IdentityCredential}} or failure.
1. Otherwise:
1. Set |account| to the result of running the [=select an account=] from the
|accountsList|.
1. If |account| is failure, return failure.
1. If |account| is failure, return (failure, true).
1. Set |accountState| to the result of running the [=compute the connection status=] algorithm
given |provider| and |account|.
1. If |accountState| is [=compute the connection status/disconnected=]:
Expand All @@ -564,7 +572,7 @@ following steps. This returns an {{IdentityCredential}} or failure.
1. Wait until the [=user agent=]'s dialogs requesting for user choice or permission to be
closed, if any are created in the previous steps.
1. Assert: |account| is not null.
1. If |permission| is false, then return failure.
1. If |permission| is false, then return (failure, true).
1. Let |credential| be the result of running the [=fetch an identity assertion=] algorithm with
|account|'s {{IdentityProviderAccount/id}}, |provider|, |config|, and
|globalObject|.
Expand Down

0 comments on commit c8609ec

Please sign in to comment.