From 82991764011791e6c5dc86b0e23884ecff12be06 Mon Sep 17 00:00:00 2001 From: Nina Satragno Date: Mon, 18 Jan 2021 15:43:32 -0500 Subject: [PATCH 1/7] Add conditional UI flow --- index.bs | 339 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 247 insertions(+), 92 deletions(-) diff --git a/index.bs b/index.bs index 0398f753a..3e72e08de 100644 --- a/index.bs +++ b/index.bs @@ -165,6 +165,8 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: opaque origin; url: concept-origin-opaque text: tuple origin; url: concept-origin-tuple text: document.domain; url:dom-document-domain + urlPrefix: form-control-infrastructure.html + text: autofill detail token; url: autofill-detail-tokens spec: url; urlPrefix: https://url.spec.whatwg.org type: dfn @@ -1153,8 +1155,8 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S : otherUI :: OPTIONAL other information used by the [=authenticator=] to inform its UI. For example, this might include the user's - {{displayName}}. [=otherUI=] is a mutable item and SHOULD NOT be bound to the [=public key credential source=] - in a way that prevents [=otherUI=] from being updated. + {{displayName}}. [=public key credential source/otherUI=] is a mutable item and SHOULD NOT be bound to the + [=public key credential source=] in a way that prevents [=public key credential source/otherUI=] from being updated. The [=authenticatorMakeCredential=] operation creates a [=public key credential source=] [=bound credential|bound=] to a @@ -1475,6 +1478,18 @@ that are returned to the caller when a new credential is created, or a new asser [=extension identifier=] → [=client extension output=] entries produced by the extension's [=client extension processing=]. + : {{PublicKeyCredential/isConditionalMediationAvailable()}} + :: {{PublicKeyCredential}} overrides this method to indicate availability for {{CredentialMediationRequirement/conditional}} + mediation. [=[WRPS]=] SHOULD verify availability before attempting to set + |options|.{{CredentialRequestOptions/mediation}} to {{CredentialMediationRequirement/conditional}}. + + Upon invocation, [TRUE] is returned if {{CredentialMediationRequirement/conditional}} [=user mediation=] is available, [FALSE] + otherwise. + + This method has no arguments and returns a Boolean value. + + Note: If this method is not present, {{CredentialMediationRequirement/conditional}} [=user mediation=] is not available. + : \[[type]] :: The {{PublicKeyCredential}} [=interface object=]'s {{Credential/[[type]]}} [=internal slot=]'s value is the string "`public-key`". @@ -1984,7 +1999,7 @@ decline the entire interaction even if a [=credential source=] is present, for e [[#sctn-op-get-assertion]] to sign a [=[RP]=]-provided challenge and other collected data into an [=authentication assertion=], which is used as a [=credential=]. -The {{CredentialsContainer/get()}} implementation [[!CREDENTIAL-MANAGEMENT-1]] calls +The {{CredentialsContainer/get()|navigator.credentials.get()}} implementation [[!CREDENTIAL-MANAGEMENT-1]] calls PublicKeyCredential.{{PublicKeyCredential/[[CollectFromCredentialStore]]()}} to collect any [=credentials=] that should be available without [=user mediation=] (roughly, this specification's [=authorization gesture=]), and if it does not find exactly one of those, it then calls PublicKeyCredential.{{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} to have @@ -1994,6 +2009,12 @@ Since this specification requires an [=authorization gesture=] to create any [=a for="PublicKeyCredential" method>\[[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors) [=internal method=] inherits the default behavior of {{Credential/[[CollectFromCredentialStore]]()|Credential.[[CollectFromCredentialStore]]()}}, of returning an empty set. +In general, the user agent SHOULD show some UI to the user to guide them in selecting and authorizing an authenticator with which +to complete the operation. By setting |options|.{{CredentialRequestOptions/mediation}} to {{CredentialMediationRequirement/conditional}}, [=[RPS]=] can indicate that a prominent modal UI should not be shown unless credentials are discovered. [=[RP]=] +script SHOULD first check that {{PublicKeyCredential/isConditionalMediationAvailable()}} returns [TRUE] in order to avoid +the possibility of causing a user-visible error to be returned if the user agent does not support +{{CredentialMediationRequirement/conditional}} [=user mediation=]. + This {{CredentialsContainer/get()|navigator.credentials.get()}} operation can be aborted by leveraging the {{AbortController}}; see [[dom#abortcontroller-api-integration]] for detailed instructions. @@ -2037,24 +2058,37 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Let |options| be the value of |options|.{{CredentialRequestOptions/publicKey}}. -1. If the {{PublicKeyCredentialRequestOptions/timeout}} member of |options| is present, check if its value lies - within a reasonable range as defined by the [=client=] and if not, correct it to the closest value lying within that range. - Set a timer |lifetimeTimer| to this adjusted value. If the {{PublicKeyCredentialRequestOptions/timeout}} member of - |options| is not present, then set |lifetimeTimer| to a [=client=]-specific default. +1. If |options|.{{CredentialRequestOptions/mediation}} is present with the value + {{CredentialMediationRequirement/conditional}}: - Recommended ranges and defaults for the {{PublicKeyCredentialRequestOptions/timeout}} member of |options| are as follows. - If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} -
- : is set to {{UserVerificationRequirement/discouraged}} - :: Recommended range: 30000 milliseconds to 180000 milliseconds. - :: Recommended default value: 120000 milliseconds (2 minutes). + 1. If |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} is not [=list/empty=], + return a {{DOMException}} whose name is "{{NotSupportedError}}", and terminate this algorithm. - : is set to {{UserVerificationRequirement/required}} or {{UserVerificationRequirement/preferred}} - :: Recommended range: 30000 milliseconds to 600000 milliseconds. - :: Recommended default value: 300000 milliseconds (5 minutes). -
+ 1. Set a timer |lifetimeTimer| to a value of infinity. - Note: The user agent should take cognitive guidelines into considerations regarding timeout for users with special needs. + Note: |lifetimeTimer| is set to a value of infinity so that the user has the entire lifetime of + the [=Document=] to interact with any <{input}> form control tagged with a `"webauthn"` [=autofill detail token=]. For example, upon the user clicking in such an input field, the user agent can render a list of discovered credentials for the user to select from, and perhaps also give the user the option to "try another way". + +1. Else: + + 1. If the {{PublicKeyCredentialRequestOptions/timeout}} member of |options| is present, check if its value lies + within a reasonable range as defined by the [=client=] and if not, correct it to the closest value lying within that range. + Set a timer |lifetimeTimer| to this adjusted value. If the {{PublicKeyCredentialRequestOptions/timeout}} member of + |options| is not present, then set |lifetimeTimer| to a [=client=]-specific default. + + Recommended ranges and defaults for the {{PublicKeyCredentialRequestOptions/timeout}} member of |options| are as follows. + If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} +
+ : is set to {{UserVerificationRequirement/discouraged}} + :: Recommended range: 30000 milliseconds to 180000 milliseconds. + :: Recommended default value: 120000 milliseconds (2 minutes). + + : is set to {{UserVerificationRequirement/required}} or {{UserVerificationRequirement/preferred}} + :: Recommended range: 30000 milliseconds to 600000 milliseconds. + :: Recommended default value: 300000 milliseconds (5 minutes). +
+ + Note: The user agent should take cognitive guidelines into considerations regarding timeout for users with special needs. 1. Let |callerOrigin| be {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)/origin}}. If |callerOrigin| is an [=opaque origin=], throw a "{{NotAllowedError}}" {{DOMException}}. @@ -2130,6 +2164,8 @@ When this method is invoked, the user agent MUST execute the following algorithm [=authenticators=] can be hot-plugged into (e.g., via USB) or discovered (e.g., via NFC or Bluetooth) by the [=client=] by various mechanisms, or permanently built into the [=client=]. +1. Let |silentlyDiscoveredCredentials| be a new [=map=] whose [=map/entry|entries=] are of the form: [=DiscoverableCredentialMetadata=] → [=authenticator=]. + 1. Start |lifetimeTimer|. 1. [=While=] |lifetimeTimer| has not expired, perform the following actions depending upon |lifetimeTimer|, @@ -2146,103 +2182,72 @@ When this method is invoked, the user agent MUST execute the following algorithm and [=set/remove=] |authenticator| from |issuedRequests|. Throw a "{{NotAllowedError}}" {{DOMException}}. : If |options|.{{CredentialRequestOptions/signal}} is present and [=AbortSignal/aborted=], + :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. Then throw the |options|.{{CredentialRequestOptions/signal}}'s [=AbortSignal/abort reason=]. - : If |issuedRequests| is empty, |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} is not empty, and no |authenticator| will become available for any [=public key credentials=] therein, - :: Indicate to the user that no eligible credential could be found. When the user acknowledges the dialog, throw a "{{NotAllowedError}}" {{DOMException}}. + :
+ If |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} + and the user interacts with an <{input}> form control with an <{input/autocomplete}> attribute whose value + contains a `"webauthn"` [=autofill detail token=], +
- Note: One way a [=client platform=] can determine that no |authenticator| will become available is by examining the {{transports}} members of the present {{PublicKeyCredentialDescriptor}} [=list/items=] of |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}, if any. For example, if all {{PublicKeyCredentialDescriptor}} [=list/items=] list only {{AuthenticatorTransport/internal}}, but all [=platform authenticator|platform=] |authenticator|s have been tried, then there is no possibility of satisfying the request. Alternatively, all {{PublicKeyCredentialDescriptor}} [=list/items=] may list {{transports}} that the [=client platform=] does not support. + :: 1. If |silentlyDiscoveredCredentials| is not [=list/empty=]: - : If an |authenticator| becomes available on this [=client device=], - :: Note: This includes the case where an |authenticator| was available upon |lifetimeTimer| initiation. + 1. Prompt the user to optionally select a [=DiscoverableCredentialMetadata=] (|credentialMetadata|) from |silentlyDiscoveredCredentials|. - 1. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} is set to - {{UserVerificationRequirement/required}} and the |authenticator| is not capable of performing [=user verification=], - [=iteration/continue=]. + Note: The prompt shown SHOULD include values from |credentialMetadata|'s [=DiscoverableCredentialMetadata/otherUI=] + such as {{PublicKeyCredentialEntity/name}} and {{PublicKeyCredentialUserEntity/displayName}}. - 1. Let |userVerification| be the effective user verification requirement for assertion, a Boolean value, as - follows. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} + 1. If the user selects a |credentialMetadata|, -
+ 1. Let |optionsCopy| be a temporary copy of |options|. - : is set to {{UserVerificationRequirement/required}} - :: Let |userVerification| be [TRUE]. + 1. Let |authenticator| be the value of |silentlyDiscoveredCredentials|[|credentialMetadata|]. - : is set to {{UserVerificationRequirement/preferred}} - :: If the |authenticator| + 1. Set |optionsCopy|.{{PublicKeyCredentialRequestOptions/allowCredentials}} to be a [=list=] containing a + single {{PublicKeyCredentialDescriptor}} [=list/item=] whose {{PublicKeyCredentialDescriptor/id}}'s value is set to + |credentialMetadata|'s [=DiscoverableCredentialMetadata/id=]'s value. -
- : is capable of [=user verification=] - :: Let |userVerification| be [TRUE]. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds| and |optionsCopy|. - : is not capable of [=user verification=] - :: Let |userVerification| be [FALSE]. -
+ 1. [=set/Append=] |authenticator| to |issuedRequests|. - : is set to {{UserVerificationRequirement/discouraged}} - :: Let |userVerification| be [FALSE]. + Issue: Nina to submit a PR to the HTML spec to add the "webauthn" autofill detail token. -
+ : If |options|.{{CredentialRequestOptions/mediation}} is not {{CredentialMediationRequirement/conditional}}, + |issuedRequests| is empty, |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} is not empty, + and no |authenticator| will become available for any [=public key credentials=] therein, + :: Indicate to the user that no eligible credential could be found. When the user acknowledges the dialog, throw a "{{NotAllowedError}}" {{DOMException}}. - 1. - If |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} -
- : [=list/is not empty=] - :: 1. Let |allowCredentialDescriptorList| be a new [=list=]. + Note: One way a [=client platform=] can determine that no |authenticator| will become available is by examining the {{transports}} members of the present {{PublicKeyCredentialDescriptor}} [=list/items=] of |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}, if any. For example, if all {{PublicKeyCredentialDescriptor}} [=list/items=] list only {{AuthenticatorTransport/internal}}, but all [=platform authenticator|platform=] |authenticator|s have been tried, then there is no possibility of satisfying the request. Alternatively, all {{PublicKeyCredentialDescriptor}} [=list/items=] may list {{transports}} that the [=client platform=] does not support. - 1. Execute a [=client platform=]-specific procedure to determine which, if any, [=public key credentials=] described by - |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} are [=bound credential|bound=] to this - |authenticator|, by matching with |rpId|, - |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/id}}, - and - |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/type}}. - Set |allowCredentialDescriptorList| to this filtered list. + : If an |authenticator| becomes available on this [=client device=], + :: Note: This includes the case where an |authenticator| was available upon |lifetimeTimer| initiation. - 1. If |allowCredentialDescriptorList| [=list/is empty=], [=continue=]. + 1. If |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} + and the |authenticator| supports the [=silentCredentialDiscovery=] operation: - 1. Let |distinctTransports| be a new [=ordered set=]. + 1. Let |collectedDiscoveredCredentialMetadata| be the result of invoking the [=silentCredentialDiscovery=] operation on |authenticator| with |rpId| as parameter. - 1. If |allowCredentialDescriptorList| has exactly one value, set - |savedCredentialIds|[|authenticator|] to |allowCredentialDescriptorList|[0].id's - value (see [here](#authenticatorGetAssertion-return-values) in [[#sctn-op-get-assertion]] for more information). + 1. [=list/For each=] |credentialMetadata| of |collectedDiscoveredCredentialMetadata|: - 1. [=list/For each=] credential descriptor |C| in |allowCredentialDescriptorList|, - [=set/append=] each value, if any, of |C|.{{transports}} to |distinctTransports|. + 1. [=map/Set=] |silentlyDiscoveredCredentials|[|credentialMetadata|] to |authenticator|. - Note: This will aggregate only distinct values of {{transports}} (for this [=authenticator=]) in - |distinctTransports| due to the properties of [=ordered sets=]. + Note: A request will be issued to this authenticator upon user selection of a credential via + interaction with a particular UI context + (see [here](#GetAssn-ConditionalMediation-Interact-FormControl) for details). - 1. If |distinctTransports| -
- : [=list/is not empty=] - :: The client selects one |transport| value from |distinctTransports|, possibly incorporating local - configuration knowledge of the appropriate transport to use with |authenticator| in making its - selection. - - Then, using |transport|, invoke the [=authenticatorGetAssertion=] operation on - |authenticator|, with |rpId|, |clientDataHash|, |allowCredentialDescriptorList|, - |userVerification|, and |authenticatorExtensions| as parameters. - - : [=list/is empty=] - :: Using local configuration knowledge of the appropriate transport to use with |authenticator|, - invoke the [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, - |clientDataHash|, |allowCredentialDescriptorList|, |userVerification|, and - |authenticatorExtensions| as parameters. -
+ 1. Else: - : [=list/is empty=] - :: Using local configuration knowledge of the appropriate transport to use with |authenticator|, invoke the - [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, |clientDataHash|, - |userVerification| and |authenticatorExtensions| as parameters. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds| and |options|. - Note: In this case, the [=[RP]=] did not supply a list of acceptable credential descriptors. Thus, the - authenticator is being asked to exercise any credential it may possess that is [=scoped=] to - the [=[RP]=], as identified by |rpId|. -
+ Note: This branch is taken if |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} + and the |authenticator| does not support the [=silentCredentialDiscovery=] operation to allow use of such authenticators during a + {{CredentialMediationRequirement/conditional}} [=user mediation=] request. - 1. [=set/Append=] |authenticator| to |issuedRequests|. + 1. [=set/Append=] |authenticator| to |issuedRequests|. : If an |authenticator| ceases to be available on this [=client device=], :: [=set/Remove=] |authenticator| from |issuedRequests|. @@ -2338,10 +2343,116 @@ When this method is invoked, the user agent MUST execute the following algorithm user without [=user consent|consent=], this step MUST NOT be executed before |lifetimeTimer| has expired. See [[#sctn-assertion-privacy]] for details. -During the above process, the user agent SHOULD show some UI to the user to guide them in the process of selecting and -authorizing an authenticator with which to complete the operation. +#### Issuing a Credential Request to an Authenticator #### {#sctn-issuing-cred-request-to-authenticator} + +This sub-algorithm of {{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} encompasses the specific UI context-independent +steps necessary for requesting a [=credential=] from a given [=authenticator=], using given {{CredentialRequestOptions}}. It is called by +{{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} from various points depending on which [=user mediation=] the +present [=authentication ceremony=] is subject to (e.g.: {{CredentialMediationRequirement/conditional}} mediation). + +This algorithm accepts the following arguments: + +
+ : authenticator + :: A [=client platform=]-specific handle identifying an [=authenticator=] presently available on this [=client platform=]. + + : savedCredentialIds + :: A [=map=] containing [=authenticator=] → [=credential ID=]. This argument will be modified in this algorithm. + + : options + :: This argument is a {{CredentialRequestOptions}} object whose + |options|.{{CredentialRequestOptions/publicKey}} member contains a {{PublicKeyCredentialRequestOptions}} + object specifying the desired attributes of the [=public key credential=] to discover. +
+ +The steps for [=issuing a credential request to an authenticator=] are as follows: + + 1. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} is set to + {{UserVerificationRequirement/required}} and the |authenticator| is not capable of performing [=user verification=], + [=iteration/continue=]. + + 1. Let |userVerification| be the effective user verification requirement for assertion, a Boolean value, as + follows. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} + +
+ + : is set to {{UserVerificationRequirement/required}} + :: Let |userVerification| be [TRUE]. + + : is set to {{UserVerificationRequirement/preferred}} + :: If the |authenticator| + +
+ : is capable of [=user verification=] + :: Let |userVerification| be [TRUE]. + + : is not capable of [=user verification=] + :: Let |userVerification| be [FALSE]. +
+ + : is set to {{UserVerificationRequirement/discouraged}} + :: Let |userVerification| be [FALSE]. + +
+ + 1. + If |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} +
+ : [=list/is not empty=] + :: 1. Let |allowCredentialDescriptorList| be a new [=list=]. + + 1. Execute a [=client platform=]-specific procedure to determine which, if any, [=public key credentials=] described by + |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} are [=bound credential|bound=] to this + |authenticator|, by matching with |rpId|, + |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/id}}, + and + |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/type}}. + Set |allowCredentialDescriptorList| to this filtered list. + + 1. If |allowCredentialDescriptorList| [=list/is empty=], [=continue=]. + + 1. Let |distinctTransports| be a new [=ordered set=]. + + 1. If |allowCredentialDescriptorList| has exactly one value, set + |savedCredentialIds|[|authenticator|] to |allowCredentialDescriptorList|[0].id's + value (see [here](#authenticatorGetAssertion-return-values) in [[#sctn-op-get-assertion]] for more information). + + 1. [=list/For each=] credential descriptor |C| in |allowCredentialDescriptorList|, + [=set/append=] each value, if any, of |C|.{{transports}} to |distinctTransports|. + + Note: This will aggregate only distinct values of {{transports}} (for this [=authenticator=]) in + |distinctTransports| due to the properties of [=ordered sets=]. + + 1. If |distinctTransports| +
+ : [=list/is not empty=] + :: The client selects one |transport| value from |distinctTransports|, possibly incorporating local + configuration knowledge of the appropriate transport to use with |authenticator| in making its + selection. + + Then, using |transport|, invoke the [=authenticatorGetAssertion=] operation on + |authenticator|, with |rpId|, |clientDataHash|, |allowCredentialDescriptorList|, + |userVerification|, and |authenticatorExtensions| as parameters. + + : [=list/is empty=] + :: Using local configuration knowledge of the appropriate transport to use with |authenticator|, + invoke the [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, + |clientDataHash|, |allowCredentialDescriptorList|, |userVerification|, and + |authenticatorExtensions| as parameters. +
+ + : [=list/is empty=] + :: Using local configuration knowledge of the appropriate transport to use with |authenticator|, invoke the + [=authenticatorGetAssertion=] operation on |authenticator| with |rpId|, |clientDataHash|, + |userVerification| and |authenticatorExtensions| as parameters. + + Note: In this case, the [=[RP]=] did not supply a list of acceptable credential descriptors. Thus, the + authenticator is being asked to exercise any credential it may possess that is [=scoped=] to + the [=[RP]=], as identified by |rpId|. +
+ ### Store an Existing Credential - PublicKeyCredential's `[[Store]](credential, sameOriginWithAncestors)` Method ### {#sctn-storeCredential} @@ -3022,7 +3133,7 @@ See [[dom#abortcontroller-api-integration]] section for detailed instructions. The [=visibility states|visibility=] and [=focus=] state of the [=Window=] object determines whether the {{PublicKeyCredential/[[Create]](origin, options, sameOriginWithAncestors)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)}} operations -should continue. When the [=Window=] object associated with the [[=Document=] loses focus, +should continue. When the [=Window=] object associated with the [=Document=] loses focus, {{PublicKeyCredential/[[Create]](origin, options, sameOriginWithAncestors)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)}} operations SHOULD be aborted. @@ -4247,6 +4358,50 @@ This operation is ignored if it is invoked in an [=authenticator session=] which or [=authenticatorGetAssertion=] operation currently in progress. +### The silentCredentialDiscovery operation ### {#sctn-op-silent-discovery} + +This is an OPTIONAL operation authenticators MAY support to enable {{CredentialMediationRequirement/conditional}} +[=user mediation=]. + +It takes the following input parameter: + +: |rpId| +:: The caller's [=RP ID=], as determined by the user agent and the client. + +When this operation is invoked, the [=authenticator=] MUST perform the following procedure: + +1. Let |collectedDiscoverableCredentialMetadata| be a new [=list=] whose [=list/items=] are + DiscoverableCredentialMetadata [=structs=] with the following [=struct/items=]: + +
+ : id + :: A [=Credential ID=]. + + : rpId + :: A [=Relying Party Identifier=]. + + : userHandle + :: A [=user handle=]. + + : otherUI + :: Other information used by the [=authenticator=] to inform its UI. +
+ +1. [=map/For each=] [=public key credential source=] |credSource| of |authenticator|'s [=credentials map=]: + + 1. If |credSource| is not a [=client-side discoverable credential=], [=iteration/continue=]. + + 1. If |credSource|.[=public key credential source/rpId=] is not |rpId|, [=iteration/continue=]. + + 1. Let |discoveredCredentialMetadata| be a new [=DiscoverableCredentialMetadata=] [=struct=] whose [=struct/items=] + are copies of |credSource|'s [=public key credential source/id=], [=public key credential source/rpId=], + [=public key credential source/userHandle=] and [=public key credential source/otherUI=]. + + 1. [=list/Append=] |discoveredCredentialMetadata| to |collectedDiscoverableCredentialMetadata|. + +1. Return |collectedDiscoverableCredentialMetadata|. + + ## String Handling ## {#sctn-strings} Authenticators may be required to store arbitrary strings chosen by a [=[RP]=], for example the {{PublicKeyCredentialEntity/name}} and {{PublicKeyCredentialUserEntity/displayName}} in a {{PublicKeyCredentialUserEntity}}. This section discusses some practical consequences of handling arbitrary strings that may be presented to humans. From dc021fbf89e65c9c4beb1398ec5258b914c0c6fd Mon Sep 17 00:00:00 2001 From: Nina Satragno Date: Wed, 15 Jun 2022 14:01:20 -0400 Subject: [PATCH 2/7] Make method return promise. --- index.bs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 3e72e08de..03015b449 100644 --- a/index.bs +++ b/index.bs @@ -1434,7 +1434,7 @@ that are returned to the caller when a new credential is created, or a new asser [SameObject] readonly attribute AuthenticatorResponse response; [SameObject] readonly attribute DOMString? authenticatorAttachment; AuthenticationExtensionsClientOutputs getClientExtensionResults(); - static boolean isConditionalMediationAvailable(); + static Promise isConditionalMediationAvailable(); };
@@ -1483,10 +1483,10 @@ that are returned to the caller when a new credential is created, or a new asser mediation. [=[WRPS]=] SHOULD verify availability before attempting to set |options|.{{CredentialRequestOptions/mediation}} to {{CredentialMediationRequirement/conditional}}. - Upon invocation, [TRUE] is returned if {{CredentialMediationRequirement/conditional}} [=user mediation=] is available, [FALSE] - otherwise. + Upon invocation, a promise is returned that resolves with a value of [TRUE] if {{CredentialMediationRequirement/conditional}} + [=user mediation=] is available, or [FALSE] otherwise. - This method has no arguments and returns a Boolean value. + This method has no arguments and returns a promise to a Boolean value. Note: If this method is not present, {{CredentialMediationRequirement/conditional}} [=user mediation=] is not available. From 98d2b5eda6a031812ec2c347a0b2ed4170ad4833 Mon Sep 17 00:00:00 2001 From: Nina Satragno Date: Wed, 15 Jun 2022 14:07:08 -0400 Subject: [PATCH 3/7] fix up pr --- index.bs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/index.bs b/index.bs index 03015b449..8b1084245 100644 --- a/index.bs +++ b/index.bs @@ -2187,11 +2187,12 @@ When this method is invoked, the user agent MUST execute the following algorithm and [=set/remove=] |authenticator| from |issuedRequests|. Then throw the |options|.{{CredentialRequestOptions/signal}}'s [=AbortSignal/abort reason=]. - :
- If |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} - and the user interacts with an <{input}> form control with an <{input/autocomplete}> attribute whose value - contains a `"webauthn"` [=autofill detail token=], -
+ +
+ If |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} + and the user interacts with an <{input}> or <{textarea}> form control with an <{input/autocomplete}> attribute whose value + contains a `"webauthn"` [=autofill detail token=], +
:: 1. If |silentlyDiscoveredCredentials| is not [=list/empty=]: @@ -2214,8 +2215,6 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. [=set/Append=] |authenticator| to |issuedRequests|. - Issue: Nina to submit a PR to the HTML spec to add the "webauthn" autofill detail token. - : If |options|.{{CredentialRequestOptions/mediation}} is not {{CredentialMediationRequirement/conditional}}, |issuedRequests| is empty, |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} is not empty, and no |authenticator| will become available for any [=public key credentials=] therein, From 2046a4d719b23332a994388b8bb46cd14178ed40 Mon Sep 17 00:00:00 2001 From: Nina Satragno Date: Wed, 15 Jun 2022 14:19:11 -0400 Subject: [PATCH 4/7] remove newline. --- index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/index.bs b/index.bs index 8b1084245..ba8057be3 100644 --- a/index.bs +++ b/index.bs @@ -2182,7 +2182,6 @@ When this method is invoked, the user agent MUST execute the following algorithm and [=set/remove=] |authenticator| from |issuedRequests|. Throw a "{{NotAllowedError}}" {{DOMException}}. : If |options|.{{CredentialRequestOptions/signal}} is present and [=AbortSignal/aborted=], - :: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. Then throw the |options|.{{CredentialRequestOptions/signal}}'s [=AbortSignal/abort reason=]. From 55bc6a9706ed613cb36eb2763cefccc0f8ea6821 Mon Sep 17 00:00:00 2001 From: Nina Satragno Date: Tue, 21 Jun 2022 15:22:52 -0400 Subject: [PATCH 5/7] Address comments. --- index.bs | 53 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/index.bs b/index.bs index ba8057be3..5adf7f1c9 100644 --- a/index.bs +++ b/index.bs @@ -2202,15 +2202,18 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. If the user selects a |credentialMetadata|, - 1. Let |optionsCopy| be a temporary copy of |options|. + 1. Let |publicKeyOptions| be a temporary copy of |options|.{{CredentialRequestOptions/publicKey}}. 1. Let |authenticator| be the value of |silentlyDiscoveredCredentials|[|credentialMetadata|]. - 1. Set |optionsCopy|.{{PublicKeyCredentialRequestOptions/allowCredentials}} to be a [=list=] containing a - single {{PublicKeyCredentialDescriptor}} [=list/item=] whose {{PublicKeyCredentialDescriptor/id}}'s value is set to - |credentialMetadata|'s [=DiscoverableCredentialMetadata/id=]'s value. + 1. Set |publicKeyOptions|.{{PublicKeyCredentialRequestOptions/allowCredentials}} to be a [=list=] containing a + single {{PublicKeyCredentialDescriptor}} [=list/item=] whose {{PublicKeyCredentialDescriptor/id}}'s value is set to + |credentialMetadata|'s [=DiscoverableCredentialMetadata/id=]'s value and whose{{PublicKeyCredentialDescriptor/id}} + value is set to |credentialMetadata|'s [=DiscoverableCredentialMetadata/type=]. - 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds| and |optionsCopy|. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds| and |publicKeyOptions|. + + 1. If that threw a {{NotAllowedError}} [=exception=], [=continue=]. 1. [=set/Append=] |authenticator| to |issuedRequests|. @@ -2239,12 +2242,15 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Else: - 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds| and |options|. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, + |savedCredentialIds| and |options|.{{CredentialRequestOptions/publicKey}}. Note: This branch is taken if |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} and the |authenticator| does not support the [=silentCredentialDiscovery=] operation to allow use of such authenticators during a {{CredentialMediationRequirement/conditional}} [=user mediation=] request. + 1. If that threw a {{NotAllowedError}} [=exception=], [=continue=]. + 1. [=set/Append=] |authenticator| to |issuedRequests|. : If an |authenticator| ceases to be available on this [=client device=], @@ -2360,16 +2366,28 @@ This algorithm accepts the following arguments: :: A [=map=] containing [=authenticator=] → [=credential ID=]. This argument will be modified in this algorithm. : options - :: This argument is a {{CredentialRequestOptions}} object whose - |options|.{{CredentialRequestOptions/publicKey}} member contains a {{PublicKeyCredentialRequestOptions}} - object specifying the desired attributes of the [=public key credential=] to discover. + :: This argument is a {{PublicKeyCredentialRequestOptions}} object specifying the desired attributes of the + [=public key credential=] to discover. + + : rpId + :: The request [=RP ID=]. + + : clientDataHash + :: The [=hash of the serialized client data=] represented by |clientDataJSON|. + + : authenticatorExtensions + :: A [=map=] containing [=extension IDs=] to the [=base64url encoding=] of the [=client extension processing=] + output for [=authenticator extensions=].
+This algorithm throws a "{{NotAllowedError}}" {{DOMException}} if the [=client=] determines that the |authenticator| is +not capable of handling the request. + The steps for [=issuing a credential request to an authenticator=] are as follows: 1. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} is set to {{UserVerificationRequirement/required}} and the |authenticator| is not capable of performing [=user verification=], - [=iteration/continue=]. + throw a "{{NotAllowedError}}" {{DOMException}}. 1. Let |userVerification| be the effective user verification requirement for assertion, a Boolean value, as follows. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} @@ -2405,11 +2423,10 @@ The steps for [=issuing a credential request to an authenticator=] are as follow |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}} are [=bound credential|bound=] to this |authenticator|, by matching with |rpId|, |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/id}}, - and - |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/type}}. + and |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/type}}. Set |allowCredentialDescriptorList| to this filtered list. - 1. If |allowCredentialDescriptorList| [=list/is empty=], [=continue=]. + 1. If |allowCredentialDescriptorList| [=list/is empty=], throw a "{{NotAllowedError}}" {{DOMException}}. 1. Let |distinctTransports| be a new [=ordered set=]. @@ -4364,7 +4381,7 @@ This is an OPTIONAL operation authenticators MAY support to enable {{CredentialM It takes the following input parameter: : |rpId| -:: The caller's [=RP ID=], as determined by the user agent and the client. +:: The caller's [=RP ID=], as determined by the [=client=]. When this operation is invoked, the [=authenticator=] MUST perform the following procedure: @@ -4372,6 +4389,9 @@ When this operation is invoked, the [=authenticator=] MUST perform the following DiscoverableCredentialMetadata [=structs=] with the following [=struct/items=]:
+ : type + :: A {{PublicKeyCredentialType}}. + : id :: A [=Credential ID=]. @@ -4392,8 +4412,9 @@ When this operation is invoked, the [=authenticator=] MUST perform the following 1. If |credSource|.[=public key credential source/rpId=] is not |rpId|, [=iteration/continue=]. 1. Let |discoveredCredentialMetadata| be a new [=DiscoverableCredentialMetadata=] [=struct=] whose [=struct/items=] - are copies of |credSource|'s [=public key credential source/id=], [=public key credential source/rpId=], - [=public key credential source/userHandle=] and [=public key credential source/otherUI=]. + are copies of |credSource|'s [=public key credential source/type=], [=public key credential source/id=], + [=public key credential source/rpId=], [=public key credential source/userHandle=] and + [=public key credential source/otherUI=]. 1. [=list/Append=] |discoveredCredentialMetadata| to |collectedDiscoverableCredentialMetadata|. From ead5a2b29f7c5f6d9d3b85e3def74f655c35a083 Mon Sep 17 00:00:00 2001 From: Nina Satragno Date: Wed, 22 Jun 2022 14:43:45 -0400 Subject: [PATCH 6/7] Address comments. --- index.bs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/index.bs b/index.bs index 5adf7f1c9..aec8919a7 100644 --- a/index.bs +++ b/index.bs @@ -2211,9 +2211,10 @@ When this method is invoked, the user agent MUST execute the following algorithm |credentialMetadata|'s [=DiscoverableCredentialMetadata/id=]'s value and whose{{PublicKeyCredentialDescriptor/id}} value is set to |credentialMetadata|'s [=DiscoverableCredentialMetadata/type=]. - 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds| and |publicKeyOptions|. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds|, + |publicKeyOptions|, |rpId|, |clientDataHash|, and |authenticatorExtensions|. - 1. If that threw a {{NotAllowedError}} [=exception=], [=continue=]. + If this returns [FALSE], [=continue=]. 1. [=set/Append=] |authenticator| to |issuedRequests|. @@ -2242,15 +2243,15 @@ When this method is invoked, the user agent MUST execute the following algorithm 1. Else: - 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, - |savedCredentialIds| and |options|.{{CredentialRequestOptions/publicKey}}. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds|, + |options|.{{CredentialRequestOptions/publicKey}}, |rpId|, |clientDataHash|, and |authenticatorExtensions|. + + If this returns [FALSE], [=continue=]. Note: This branch is taken if |options|.{{CredentialRequestOptions/mediation}} is {{CredentialMediationRequirement/conditional}} and the |authenticator| does not support the [=silentCredentialDiscovery=] operation to allow use of such authenticators during a {{CredentialMediationRequirement/conditional}} [=user mediation=] request. - 1. If that threw a {{NotAllowedError}} [=exception=], [=continue=]. - 1. [=set/Append=] |authenticator| to |issuedRequests|. : If an |authenticator| ceases to be available on this [=client device=], @@ -2352,9 +2353,9 @@ When this method is invoked, the user agent MUST execute the following algorithm #### Issuing a Credential Request to an Authenticator #### {#sctn-issuing-cred-request-to-authenticator} This sub-algorithm of {{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} encompasses the specific UI context-independent -steps necessary for requesting a [=credential=] from a given [=authenticator=], using given {{CredentialRequestOptions}}. It is called by -{{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} from various points depending on which [=user mediation=] the -present [=authentication ceremony=] is subject to (e.g.: {{CredentialMediationRequirement/conditional}} mediation). +steps necessary for requesting a [=credential=] from a given [=authenticator=], using given {{PublicKeyCredentialRequestOptions}}. +It is called by {{PublicKeyCredential/[[DiscoverFromExternalSource]]()}} from various points depending on which [=user mediation=] +the present [=authentication ceremony=] is subject to (e.g.: {{CredentialMediationRequirement/conditional}} mediation). This algorithm accepts the following arguments: @@ -2380,14 +2381,14 @@ This algorithm accepts the following arguments: output for [=authenticator extensions=].
-This algorithm throws a "{{NotAllowedError}}" {{DOMException}} if the [=client=] determines that the |authenticator| is -not capable of handling the request. +This algorithm returns [FALSE] if the [=client=] determines that the |authenticator| is not capable of handling the request, or [TRUE] if +the request was issued successfully. The steps for [=issuing a credential request to an authenticator=] are as follows: 1. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} is set to {{UserVerificationRequirement/required}} and the |authenticator| is not capable of performing [=user verification=], - throw a "{{NotAllowedError}}" {{DOMException}}. + return [FALSE]. 1. Let |userVerification| be the effective user verification requirement for assertion, a Boolean value, as follows. If |options|.{{PublicKeyCredentialRequestOptions/userVerification}} @@ -2426,7 +2427,7 @@ The steps for [=issuing a credential request to an authenticator=] are as follow and |options|.{{PublicKeyCredentialRequestOptions/allowCredentials}}.{{PublicKeyCredentialDescriptor/type}}. Set |allowCredentialDescriptorList| to this filtered list. - 1. If |allowCredentialDescriptorList| [=list/is empty=], throw a "{{NotAllowedError}}" {{DOMException}}. + 1. If |allowCredentialDescriptorList| [=list/is empty=], return [FALSE]. 1. Let |distinctTransports| be a new [=ordered set=]. @@ -2468,6 +2469,8 @@ The steps for [=issuing a credential request to an authenticator=] are as follow the [=[RP]=], as identified by |rpId|. + 1. Return [TRUE]. + ### Store an Existing Credential - PublicKeyCredential's `[[Store]](credential, sameOriginWithAncestors)` Method ### {#sctn-storeCredential} From 3fc83122d009fbc14ec5b04c1726bd62aaf3479c Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Wed, 22 Jun 2022 20:47:03 +0200 Subject: [PATCH 7/7] Fix Bikeshed errors (#4) Fixes: ``` FATAL ERROR: Line 2246 isn't indented enough (needs 1 indent) to be valid Markdown: " |savedCredentialIds| and |options|.{{CredentialRequestOptions/publicKey}}." LINE ~2379: No 'dfn' refs found for 'extension ids'. [=extension IDs=] LINE ~4158: Multiple possible 'dfn' local refs for 'type'. Randomly chose one of them; other instances might get a different random choice. [=type=] ``` Co-authored-by: Nina Satragno --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index aec8919a7..2fe35f0e0 100644 --- a/index.bs +++ b/index.bs @@ -2377,7 +2377,7 @@ This algorithm accepts the following arguments: :: The [=hash of the serialized client data=] represented by |clientDataJSON|. : authenticatorExtensions - :: A [=map=] containing [=extension IDs=] to the [=base64url encoding=] of the [=client extension processing=] + :: A [=map=] containing [=extension identifiers=] to the [=base64url encoding=] of the [=client extension processing=] output for [=authenticator extensions=]. @@ -4159,7 +4159,7 @@ When this operation is invoked, the [=authenticator=] MUST perform the following 1. [=list/For each=] |descriptor| of |excludeCredentialDescriptorList|: 1. If [=credential id/looking up=] |descriptor|.{{PublicKeyCredentialDescriptor/id}} in this authenticator - returns non-null, and the returned [=list/item=]'s [=RP ID=] and [=type=] match + returns non-null, and the returned [=list/item=]'s [=RP ID=] and [=public key credential source/type=] match |rpEntity|.{{PublicKeyCredentialRpEntity/id}} and |excludeCredentialDescriptorList|.{{PublicKeyCredentialDescriptor/type}} respectively, then collect an [=authorization gesture=] confirming [=user