diff --git a/index.bs b/index.bs index 5aa5fbf29..e99295823 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 \[[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. @@ -2099,24 +2120,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}}. @@ -2192,6 +2226,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|, @@ -2212,99 +2248,73 @@ 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 |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}> or <{textarea}> 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 |publicKeyOptions| be a temporary copy of |options|.{{CredentialRequestOptions/publicKey}}. - : 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 |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=]. -
- : is capable of [=user verification=] - :: Let |userVerification| be [TRUE]. + 1. Execute the [=issuing a credential request to an authenticator=] algorithm with |authenticator|, |savedCredentialIds|, + |publicKeyOptions|, |rpId|, |clientDataHash|, and |authenticatorExtensions|. - : is not capable of [=user verification=] - :: Let |userVerification| be [FALSE]. -
+ If this returns [FALSE], [=continue=]. - : is set to {{UserVerificationRequirement/discouraged}} - :: Let |userVerification| be [FALSE]. + 1. [=set/Append=] |authenticator| to |issuedRequests|. -
+ : 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|, + |options|.{{CredentialRequestOptions/publicKey}}, |rpId|, |clientDataHash|, and |authenticatorExtensions|. - 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|. -
+ If this returns [FALSE], [=continue=]. - 1. [=set/Append=] |authenticator| to |issuedRequests|. + 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|. : If an |authenticator| ceases to be available on this [=client device=], :: [=set/Remove=] |authenticator| from |issuedRequests|. @@ -2400,10 +2410,129 @@ 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 {{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: + +
+ : 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 {{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 identifiers=] to the [=base64url encoding=] of the [=client extension processing=] + output for [=authenticator extensions=]. +
+ +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=], + return [FALSE]. + + 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=], return [FALSE]. + + 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|. +
+ + 1. Return [TRUE]. + ### Store an Existing Credential - PublicKeyCredential's `[[Store]](credential, sameOriginWithAncestors)` Method ### {#sctn-storeCredential} @@ -3182,7 +3311,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. @@ -4190,7 +4319,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 @@ -4407,6 +4536,54 @@ 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 [=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=]: + +
+ : type + :: A {{PublicKeyCredentialType}}. + + : 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/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|. + +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.