-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make create() and get() abortable #544
Changes from all commits
ed25b6c
31a8f85
9c3940f
be43665
9ce4331
78d6d2c
9ddf29d
5f543b8
d8fd53b
c9b40d5
d492a50
2934f9e
a1be0f6
28f52af
5fada18
6a011d2
5fb2f8c
51706b3
5e4a7b0
d6d6c19
a76de0b
97f0ae2
8622aea
e8ca2be
84c12bb
2263888
12c943b
4750a54
30a5690
fa7c06b
f21e17d
6181caf
0d5bba1
352223c
298677f
549e659
ad5a888
c142b5a
3fa4a3f
14a7659
2cb344c
2430dcd
ad85e75
78b0912
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,10 +91,20 @@ spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-creden | |
for: CredentialsContainer | ||
type: method | ||
text: create(); url: dom-credentialscontainer-create | ||
type: dfn | ||
text: signal | ||
|
||
spec: mixed-content; urlPrefix: www.w3.org/TR/mixed-content/ | ||
type: dfn | ||
text: a priori authenticated | ||
|
||
spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/ | ||
type: dfn | ||
text: visibility states | ||
|
||
spec: WHATWG HTML; urlPrefix: https://html.spec.whatwg.org/ | ||
type: dfn | ||
text: focus | ||
</pre> <!-- class=anchors --> | ||
|
||
<pre class="link-defaults"> | ||
|
@@ -570,7 +580,9 @@ To support obtaining assertions via {{CredentialsContainer/get()|navigator.crede | |
{{CredentialsContainer/create()|navigator.credentials.create()}} to request the creation of a new [=credential key pair=] | ||
and {{PublicKeyCredential}}, managed by an [=authenticator=]. | ||
On success, the returned {{promise}} will be resolved with a {{PublicKeyCredential}} containing an | ||
{{AuthenticatorAttestationResponse}} object. | ||
{{AuthenticatorAttestationResponse}} object. This {{CredentialsContainer/create()|navigator.credentials.create()}} | ||
operation can be aborted by leveraging the {{AbortController}}; see | ||
[[dom#abortcontroller-api-integration]] for detailed instructions. | ||
|
||
Note: This algorithm is synchronous; the {{Promise}} resolution/rejection is handled by | ||
{{CredentialsContainer/create()|navigator.credentials.create()}}. | ||
|
@@ -688,6 +700,10 @@ When this method is invoked, the user agent MUST execute the following algorithm | |
|
||
1. Let |clientDataHash| be the [=hash of the serialized client data=] represented by |clientDataJSON|. | ||
|
||
1. If the <code>|options|.{{CredentialCreationOptions/signal}}</code> is [=present=] and its | ||
[=AbortSignal/aborted flag=] is set to true, return a {{DOMException}} whose name is "{{AbortError}}" | ||
and terminate this algorithm. | ||
|
||
1. Start |lifetimeTimer|. | ||
|
||
1. Let |issuedRequests| be a new [=ordered set=]. | ||
|
@@ -735,6 +751,12 @@ When this method is invoked, the user agent MUST execute the following algorithm | |
:: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| | ||
and [=set/remove=] |authenticator| from |issuedRequests|. | ||
|
||
: If the <code>|options|.{{CredentialCreationOptions/signal}}</code> is [=present=] and its | ||
[=AbortSignal/aborted flag=] is set to true, | ||
:: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] | ||
operation on |authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. Then return a {{DOMException}} | ||
whose name is "{{AbortError}}" and terminate this algorithm. | ||
|
||
: If any |authenticator| returns a status indicating that the user cancelled the operation, | ||
:: 1. [=set/Remove=] |authenticator| from |issuedRequests|. | ||
2. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on | ||
|
@@ -906,6 +928,10 @@ method is invoked, the user agent MUST: | |
|
||
1. Let |clientDataHash| be the [=hash of the serialized client data=] represented by |clientDataJSON|. | ||
|
||
1. If the <code>|options|.{{CredentialRequestOptions/signal}}</code> is [=present=] and its | ||
[=AbortSignal/aborted flag=] is set to true, return a {{DOMException}} whose name is "{{AbortError}}" | ||
and terminate this algorithm. | ||
|
||
1. Let |issuedRequests| be a new [=ordered set=]. | ||
|
||
1. Let |authenticator| be a platform-specific handle whose value identifies an [=authenticator=]. | ||
|
@@ -985,6 +1011,12 @@ method is invoked, the user agent MUST: | |
:: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on | ||
|authenticator| and [=set/remove=] |authenticator| from |issuedRequests|. | ||
|
||
: If the {{CredentialRequestOptions/signal}} member is [=present=] and the [=AbortSignal/aborted flag=] is set to | ||
true, | ||
:: [=set/For each=] |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation on |authenticator| | ||
and [=set/remove=] |authenticator| from |issuedRequests|. Then | ||
return a {{DOMException}} whose name is "{{AbortError}}" and terminate this algorithm. | ||
|
||
: If any |authenticator| returns a status indicating that the user cancelled the operation, | ||
:: 1. [=set/Remove=] |authenticator| from |issuedRequests|. | ||
2. [=set/For each=] remaining |authenticator| in |issuedRequests| invoke the [=authenticatorCancel=] operation | ||
|
@@ -1089,7 +1121,6 @@ but short enough that the dangling promise will still be resolved in a reasonabl | |
|
||
</div> | ||
|
||
|
||
## Authenticator Responses (interface <dfn interface>AuthenticatorResponse</dfn>) ## {#iface-authenticatorresponse} | ||
|
||
[=Authenticators=] respond to [=[RP]=] requests by returning an object derived from the | ||
|
@@ -1418,14 +1449,41 @@ an assertion. Its {{PublicKeyCredentialRequestOptions/challenge}} member must be | |
:: This optional member contains a list of {{PublicKeyCredentialDescriptor}} object representing [=public key credentials=] | ||
acceptable to the caller, in decending order of the caller's preference (the first item in the list is the most | ||
preferred credential, and so on down the list). | ||
|
||
: <dfn>extensions</dfn> | ||
:: This optional member contains additional parameters requesting additional processing by the client and authenticator. | ||
For example, if transaction confirmation is sought from the user, then the prompt string might be included as an | ||
extension. | ||
</dl> | ||
|
||
|
||
## Abort operations with `AbortSignal` ## {#abortoperation} | ||
|
||
Developers are encouraged to leverage the {{AbortController}} to manage the | ||
{{PublicKeyCredential/[[Create]](options)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} operations. | ||
See [[dom#abortcontroller-api-integration]] section for detailed instructions. | ||
|
||
Note: [[dom#abortcontroller-api-integration]] section specifies that web platform APIs integrating with the | ||
{{AbortController}} must reject the promise immediately once the [=AbortSignal/aborted flag=] is set. | ||
Given the complex inheritance and parallelization structure of the {{PublicKeyCredential/[[Create]](options)}} | ||
and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} methods, the algorithms for the two APIs fulfills this | ||
requirement by checking the [=AbortSignal/aborted flag=] in three places. In the case of | ||
{{PublicKeyCredential/[[Create]](options)}}, the aborted flag is checked first in | ||
[[credential-management-1#algorithm-create]] right before calling {{Credential/[[Create]](options)}}, | ||
then in [[#createCredential]] right before authenticator sessions start, and finally | ||
during authenticator sessions. The same goes for | ||
{{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}}. | ||
|
||
The [=visibility states|visibility=] and [=focus=] state of the [=Window=] object determines whether the | ||
{{PublicKeyCredential/[[Create]](options)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} operations | ||
should continue. When the [=Window=] object associated with the [[=Document=] loses focus, | ||
{{PublicKeyCredential/[[Create]](options)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](options)}} operations | ||
SHOULD be aborted. | ||
|
||
Issue: The WHATWG HTML WG is discussing whether to provide a hook when a browsing context gains or | ||
loses focuses. If a hook is provided, the above paragraph will be updated to include the hook. | ||
See [WHATWG HTML WG Issue #2711](https://github.com/whatwg/html/issues/2711) for more details. | ||
|
||
## Authentication Extensions (typedef <dfn>AuthenticationExtensions</dfn>) ## {#iface-authentication-extensions} | ||
|
||
<pre class="idl"> | ||
|
@@ -3754,6 +3812,42 @@ extension for transaction authorization. | |
}); | ||
</pre> | ||
|
||
## Aborting Authentication Operations ## {#sample-aborting} | ||
|
||
The below example shows how a developer may use the AbortSignal parameter to abort a | ||
credential registration operation. A similiar procedure applies to an authentication operation. | ||
|
||
<pre class="example" highlight="js"> | ||
const authAbortController = new AbortController(); | ||
const authAbortSignal = authAbortController.signal; | ||
|
||
authAbortSignal.onabort = function () { | ||
// Once the page knows the abort started, inform user it is attempting to abort. | ||
} | ||
|
||
var options = { | ||
// A list of options. | ||
} | ||
|
||
navigator.credentials.create({ | ||
publicKey: options, | ||
signal: authAbortSignal}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
..? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the current design is that the signal can be a separate field (as described in the example and in my other comment). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, doh, nevermind, sorry. |
||
.then(function (attestation) { | ||
// Register the user. | ||
}).catch(function (error) { | ||
if (error == "AbortError") { | ||
// Inform user the credential hasn't been created. | ||
// Let the server know a key hasn't been created. | ||
} | ||
}); | ||
|
||
// Assume widget shows up whenever auth occurs. | ||
if (widget == "disappear") { | ||
authAbortSignal.abort(); | ||
|
||
} | ||
</pre> | ||
|
||
|
||
## Decommissioning ## {#sample-decommissioning} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
above is helpful (nice!) but will need updating per however we end up polishing this abort functionality between webauthn & credman.