diff --git a/spec/index.bs b/spec/index.bs index 1106d40a..c79d19ed 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -611,7 +611,65 @@ dictionary DisconnectedAccount { -### The CredentialRequestOptions ### {#browser-api-credential-request-options} +## The IdentityCredentialError Interface ## {#browser-api-identity-credential-error-interface} + + +This specification introduces a new type of {{DOMException}}, the {{IdentityCredentialError}}. It +is used when the [=user agent=] does not receive an identity assertion after the user has requested +to use a federated account. + +
+dictionary IdentityCredentialErrorInit {
+  DOMString error;
+  DOMString url;
+};
+
+ +
+  [Exposed=Window, SecureContext]
+  interface IdentityCredentialError : DOMException {
+    constructor(optional DOMString message = "", optional IdentityCredentialErrorInit options = {});
+    readonly attribute DOMString error;
+    readonly attribute DOMString url;
+  };
+
+ +
+To create an IdentityCredentialError given an {{IdentityCredentialErrorInit}} |options| +and a |globalObject|, run the following steps: + 1. Let |error| be a [=new=] {{IdentityCredentialError}} with |globalObject|'s + [=relevant realm=]. + 1. Set |error|'s {{DOMException/message}} to "IdentityCredentialError". + 1. Set |error|.{{IdentityCredentialError/error}} to |options|.{{IdentityCredentialError/error}} + if it is present in |options|, or to "" otherwise. + 1. Set |error|.{{IdentityCredentialError/url}} to |options|.{{IdentityCredentialError/url}} + if it is present in |options|, or to "" otherwise. + 1. Return |error|. +
+ +
+Given a |realm|, a {{DOMString}} |message|, and an {{IdentityCredentialErrorInit}} |options|, the +{{IdentityCredentialError/constructor()}} must run the following steps: + 1. Invoke the {{DOMException}}'s {{DOMException/constructor()}}, passing |realm| and |message|. + 1. Set this.{{IdentityCredentialError/error}} to |options|.{{IdentityCredentialError/error}} + if it is present in |options|, or to "" otherwise. + 1. Set this.{{IdentityCredentialError/url}} to |options|.{{IdentityCredentialError/url}} + if it is present in |options|, or to "" otherwise. +
+ +
+ : {{IdentityCredentialError/error}} + :: The {{IdentityCredentialError/error}}'s attribute getter returns the value it is set to. + It represents the type of error which resulted in an {{IdentityCredential}} not being created. + An [=IDP=] MUST NOT expose sensitive user information in this field, since it is exposed to + the [=RP=]. + : {{IdentityCredentialError/url}} + :: The {{IdentityCredentialError/url}}'s attribute getter returns the value it is set to. + It represents a URL where the user can learn more information about the error. +
+ + +## The CredentialRequestOptions ## {#browser-api-credential-request-options} This section defines the dictionaries passed into the JavaScript call: @@ -707,7 +765,7 @@ dictionary IdentityProviderRequestOptions : IdentityProviderConfig { -### The \[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) internal method ### {#browser-api-rp-sign-in} +## The \[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) internal method ## {#browser-api-rp-sign-in} The {{Credential/[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)}} @@ -745,7 +803,7 @@ requests. When the {{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). +{{IdentityCredential}} or throws an error to the caller. 1. Assert: These steps are running [=in parallel=]. 1. If @@ -783,7 +841,8 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu 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|. + 1. Otherwise, return |credential| (this may throw, since it may be an + {{IdentityCredentialError}}). @@ -791,14 +850,15 @@ algorithm is invoked, the user agent MUST execute the following steps. This retu 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=]. +agent UI, and creates the {{IdentityCredential}} or throws an exception which is then returned or +thrown to the [=RP=].
-To create an IdentityCredential given a [=sequence=] of {{IdentityProviderRequestOptions}} -|providerList|, 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. +To create an IdentityCredential given a [=sequence=] of +{{IdentityProviderRequestOptions}} |providerList|, a {{CredentialRequestOptions}} |options|, and a +|globalObject|, run the following steps. This returns an {{IdentityCredential}}, an +{{IdentityCredentialError}}, or a pair (failure, bool), where the bool indicates whether to throw +the exception immediately. 1. Assert: These steps are running [=in parallel=]. 1. Let |mode| be |options|'s {{IdentityCredentialRequestOptions/mode}}. 1. If |mode| is {{IdentityCredentialRequestOptionsMode/active}}: @@ -951,8 +1011,9 @@ the exception thrown. 1. Otherwise, |value| is a [=list=] of accounts. [=list/Extend=] |allAccounts| with |value|. 1. Also include a UI affordance to close the dialog. If the user closes this dialog, return (failure, true). - 1. Show accounts step: if |allAccounts| is not [=list/empty=], also add UI to present the account options to the user. - If the user selects an account, perform the following steps: + 1. Show accounts step: if |allAccounts| is not + [=list/empty=], also add UI to present the account options to the user. If the user selects + an account, perform the following steps: 1. Set |selectedAccount| to the chosen {{IdentityProviderAccount}}. 1. Close the dialog. 1. If the [=user agent=] created any dialogs requesting user choice or permission in the previous @@ -962,6 +1023,21 @@ the exception thrown. 1. Let |credential| be the result of running the [=fetch an identity assertion=] algorithm with |selectedAccount|'s {{IdentityProviderAccount/id}}, |permissionRequested|, |isAutoSelected|, |provider|, |config|, and |globalObject|. + 1. If |credential| is an {{IdentityCredentialError}}: + 1. The [=user agent=] MUST show UI to the user indicating that the identity assertion fetch + has failed. + 1. The [=user agent=] SHOULD use the {{IdentityCredentialError/error}} in its UI to provide + a more specific error message to the user. For instance, if the value is one of + "invalid_request", "unauthorized_client", "access_denied", "server_error", and + "temporarily_unavailable", the [=user agent=] may note the reason in a user-friendly + manner. See [here](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1) for + more details about these. + 1. The [=user agent=] MAY use the {{IdentityCredentialError/url}} to display a hyperlink + in its UI so the user can click on it to learn more information about the error message. + 1. Wait until the UI is acknowledged or dismissed by the user. + + Note: this wait means the [=user agent=] rejects the call only after the UI has been + closed by the user. 1. Return |credential|.
@@ -1121,8 +1197,8 @@ or failure. 1. If |wellKnown|.{{IdentityProviderWellKnown/accounts_endpoint}} and |wellKnown|.{{IdentityProviderWellKnown/login_url}} are set: 1. Let |well_known_accounts_url| be the result of [=computing the manifest URL=] with - |provider|, |wellKnown|.{{IdentityProviderWellKnown/accounts_endpoint}}, - and |globalObject|. + |provider|, |wellKnown|.{{IdentityProviderWellKnown/accounts_endpoint}}, and + |globalObject|. 1. Let |well_known_login_url| be the result of [=computing the manifest URL=] with |provider|, |wellKnown|.{{IdentityProviderWellKnown/login_url}}, and |globalObject|. 1. If |well_known_accounts_url| is not [=url/equal=] to |accounts_url|, return failure. @@ -1308,17 +1384,23 @@ To fetch the account picture given an {{IdentityProviderAccount}} |ac 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=]. +the token or error that will be provided to the [=RP=].
To fetch an identity assertion given a {{USVString}} |accountId|, a boolean permissionRequested, a boolean |isAutoSelected|, an {{IdentityProviderRequestOptions}} |provider|, an {{IdentityProviderAPIConfig}} |config|, - and |globalObject|, run the following steps. This returns an {{IdentityCredential}} or failure. + and |globalObject|, run the following steps. This returns an {{IdentityCredential}} or an + {{IdentityCredentialError}}. 1. Let |tokenUrl| be the result of [=computing the manifest URL=] given |provider|, |config|["{{IdentityProviderAPIConfig/id_assertion_endpoint}}"], and |globalObject|. - 1. If |tokenUrl| is failure, return failure. - 1. Create a list: let |list| be a list with the following entries: + 1. If |tokenUrl| is failure: + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |globalObject| to + let |error| be the result of [=create an IdentityCredentialError=] given {} and + |globalObject|. + 1. Wait for |error| to be set, and return it. + 1. Create a list: let |list| be a list with the + following entries: 1. ("client_id", |provider|'s {{IdentityProviderConfig/clientId}}) 1. ("nonce", |provider|'s {{IdentityProviderRequestOptions/nonce}}) 1. ("account_id", |accountId|) @@ -1358,17 +1440,38 @@ To fetch an identity assertion given a {{USVString}} 1. Let |credential| be null. 1. [=Fetch request=] with |request| and |globalObject|, and with processResponseConsumeBody set to the following steps given a response |response| and |responseBody|: + 1. If |responseBody| is null or failure, set |credential| to the result of + [=create an IdentityCredentialError=] with {} and |globalObject|, and return. 1. Let |json| be the result of [=extract the JSON fetch response=] from |response| and |responseBody|. 1. [=converted to an IDL value|Convert=] |json| to an {{IdentityAssertionResponse}}, |token|. - 1. If one of the previous two steps threw an exception, set |credential| to failure - and return. - 1. If neither {{IdentityAssertionResponse/token}} nor - {{IdentityAssertionResponse/continue_on}} was specified, set |credential| to failure - and return. - 1. If {{IdentityAssertionResponse/token}} was specified, let |tokenString| + 1. If one of the previous two steps threw an exception, set |credential| to the result of + [=create an IdentityCredentialError=] with {} and |globalObject|, and return. + 1. If {{IdentityAssertionResponse/error}} was specified, let |errorInit| be the value and: + 1. If |errorInit|.{{IdentityCredentialErrorInit/url}} is present: + 1. Let |errorUrl| be the result of running [=parse url=] given + |errorInit|.{{IdentityCredentialErrorInit/url}} (the relative URL), + |globalObject|, and |tokenUrl| (the base URL). + 1. If |errorUrl|'s [=url/host=]'s [=host/registrable domain=] + is not equal to |tokenUrl|'s, set |errorUrl| to failure. + 1. If |errorUrl| is not a [=potentially trustworthy URL=], set set |errorUrl| to + failure. + 1. If |errorUrl| is failure, set |errorInit|.{{IdentityCredentialErrorInit/url}} + to "". Otherwise, set |errorInit|.{{IdentityCredentialErrorInit/url}} to + |errorUrl|. + 1. Set |credential| to the result of [=create an IdentityCredentialError=] with + |errorInit|, and |globalObject|. + 1. Otherwise, if |response|'s [=response/status=] is not an [=ok status=]: + 1. Set |credential| to the result of [=create an IdentityCredentialError=] with {} and + |globalObject|. + 1. The user agent MAY set |credential|'s {{IdentityCredentialError/error}} based on + |response|'s [=response/status=]. For example, if the [=response/status=] is 500, it + could set it to "server_error", and if the [=response/status=] is 503, it could set + it to "temporarily_unavailable". + 1. Otherwise, if {{IdentityAssertionResponse/token}} was specified, let |tokenString| be |token|'s {{IdentityAssertionResponse/token}}. - 1. Otherwise, run these steps [=in parallel=]: + 1. Otherwise, if {{IdentityAssertionResponse/continue_on}} was specified, run these steps + [=in parallel=]: 1. Let |continueOnUrl| be the result of running [=parse url=] with |token|'s {{IdentityAssertionResponse/continue_on}} and |globalObject|. 1. If |continueOnUrl| is failure, set |credential| to failure and return. @@ -1378,6 +1481,8 @@ To fetch an identity assertion given a {{USVString}} 1. If |tokenPair| is failure, set |credential| to failure and return. 1. Let |tokenString| be the first entry of |tokenPair|. 1. If the second entry of |tokenPair| is not null, set |accountId| to that second entry. + 1. Otherwise, set |credential| to a the result of [=create an IdentityCredentialError=] with + {} and |globalObject|, 1. Wait for |tokenString| or |credential| to be set. 1. If |credential| is set: 1. Assert that |credential| is set to failure. @@ -1424,12 +1529,13 @@ An extension may add the following steps after the [=fetch identity assertion/cr instead check `disclosure_shown_for`.
- +<pre class="idl"> dictionary IdentityAssertionResponse { USVString token; USVString continue_on; + IdentityCredentialErrorInit error; }; - + ### Extension: Request permission to sign-up ### {#request-permission-signup} @@ -1580,7 +1686,7 @@ To fetch request given a [=/request=] |request|, |globalObject|, and
-When computing the manifest URL given an {{IdentityProviderRequestOptions}} |provider|, a +When computing the manifest URL given an {{IdentityProviderConfig}} |provider|, a [=string=] |manifestString|, and |globalObject|, perform the following steps. This returns a URL or failure. 1. Let |configUrl| be the result of running [=parse url=] with |provider|'s @@ -2234,9 +2340,13 @@ Every {{IdentityAssertionResponse}} is expected to have members with the followi :: The resulting token. : continue_on :: A URL that the user agent will open in a popup to finish the authentication process. + : error + :: A dictionary containing the error that occurred when the ID assertion was fetched. -Only one of `token` and `continue_on` should be specified. +Only one of `token`, `continue_on`, or `error` should be specified. When multiple are specified, +the order of processing is [`error`, `token`, `continue_on`], so the first encountered will be used +in the response. The content of the {{IdentityAssertionResponse/token}} is opaque to the user agent and can contain anything that the [=IDP=] would like to pass to the