Define "present credential requests" algorithm.#419
Define "present credential requests" algorithm.#419marcoscaceres wants to merge 12 commits intomainfrom
Conversation
26f5b15 to
a98d215
Compare
…if AbortSignal races with picker result rdar://163295172 https://bugs.webkit.org/show_bug.cgi?id=305363 Reviewed by Pascoe. Fix race and crash in CredentialRequestCoordinator by settling promises only after picker teardown and safely handling abort reasons. Ensure credential requests always settle after the picker UI has fully torn down. This change: - Defers promise settlement until the picker dismiss callback fires - Better handles aborts during presentation and teardown - Avoids capturing unprotected JSValues across async boundaries - Keeps coordinator state transitions more consistent (with better checks) It also more closely follows the spec: w3c-fedid/digital-credentials#420 w3c-fedid/digital-credentials#419 * LayoutTests/imported/w3c/web-platform-tests/digital-credentials/get.tentative.https-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/digital-credentials/non-fully-active.https-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/digital-credentials/non-fully-active.https.html: * Source/WebCore/Modules/identity/CredentialRequestCoordinator.cpp: (WebCore::CredentialRequestCoordinator::PickerStateGuard::PickerStateGuard): (WebCore::CredentialRequestCoordinator::PickerStateGuard::~PickerStateGuard): (WebCore::CredentialRequestCoordinator::setState): (WebCore::CredentialRequestCoordinator::prepareCredentialRequest): (WebCore::CredentialRequestCoordinator::handleDigitalCredentialsPickerResult): (WebCore:: const): (WebCore::CredentialRequestCoordinator::dismissPickerAndSettle): (WebCore::CredentialRequestCoordinator::abortPicker): (WebCore::CredentialRequestCoordinator::contextDestroyed): (WebCore::CredentialRequestCoordinator::~CredentialRequestCoordinator): (): Deleted. (WebCore::CredentialRequestCoordinator::presentPicker): Deleted. (WebCore::CredentialRequestCoordinator::finalizeDigitalCredential): Deleted. * Source/WebCore/Modules/identity/CredentialRequestCoordinator.h: * Source/WebCore/Modules/identity/DigitalCredential.cpp: (WebCore::DigitalCredential::discoverFromExternalSource): * Source/WebCore/SaferCPPExpectations/UncountedCallArgsCheckerExpectations: Canonical link: https://commits.webkit.org/305868@main
index.html
Outdated
There was a problem hiding this comment.
Can this be removed then?
| |document|'s [=relevant settings object=]'s [=environment settings | ||
| object/origin=], and |document|'s [=Document/origin=]. | ||
| </li> | ||
| <li>Present a [=credential chooser=] with |requestData| and wait for the |
There was a problem hiding this comment.
[=credential chooser=]
The credential choose linked here is the CredMan chooser which is different from the chooser intended by this algorithm I assume.
There was a problem hiding this comment.
Ok, yeah... this is where the "digital wallet" concept would have helped.... I guess even then, it would still be "show a UI to select a digital wallet with request data" and the digital wallet itself is a [=credential chooser=].
Could you help me with the wording here, @mohamedamir ... or we can come up with something together when we next chat?
There was a problem hiding this comment.
Here is one proposal:
What do you think that we define in our spec a digital credentials picker
And define as the UI displayed by the underlying platform together with digital wallets to let the user select a digital credentials in response to a digital credential presentation request.
And we can then refer to that one in our spec.
WDYT?
Happy to discuss/brainstorm in our weekly as well
There was a problem hiding this comment.
Yep, I'm fine with that.
| </li> | ||
| <li>If the user cancels the operation or no credential was selected: | ||
| <ol> | ||
| <li>Let |error| be a newly created {{"AbortError"}} {{DOMException}}. |
There was a problem hiding this comment.
Why AbortError when no credential was selected or when the user cancels the operation?
There was a problem hiding this comment.
In both cases, "the operation was aborted [by the user]." I don't think we should distinguish them. User cancelling the operation is generally an AbortError.
There was a problem hiding this comment.
I disagree :-)
in webauthn get-algorithm-step 16
If the user exercises a user agent user-interface option to cancel the process,
For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator
and remove authenticator from issuedRequests.
Return a DOMException whose name is "NotAllowedError".
and even more explicit in the level 3
AbortError The ceremony was cancelled by an AbortController.
See § 5.6 Abort Operations with AbortSignal and § 1.3.4 Aborting Authentication Operations.
.
.
.
NotAllowedError A catch-all error covering a wide range of possible reasons,
including common ones like the user canceling out of the ceremony.
Some of these causes are documented throughout this spec, while others are client-specific.
And Firefox even fixed a bug related to that for webauthn.
CredMan however, returns null when cancelling the credential chooser IIUC.
But I do think we shouldn't mix both, user cancelling and developer cancelling the request
There was a problem hiding this comment.
This spec is not Web Auth and we can do better. Using a catchall is not a good thing. It means developers will rely on error messages. People criticize Cred Man and Web Auth AFAIK for not using a range of exceptions.
We can elevate this to the TAG if need be, but seems like a not great use of time.
I’m strongly of the opinion that this should be an AbortError. We have a great range of exception types for a reason - we should use them.
| </li> | ||
| </ol> | ||
| </li> | ||
| <li>If the platform returns a platform-specific error: |
There was a problem hiding this comment.
This is the first mention of the platform, right?
So far it sounded like the browser is doing all of it.
Am I overlooking something?
There was a problem hiding this comment.
You are right. However, presenting the UI and so on was presumedly done by the platform too... should clarify that.
For what it's worth, in WebKit, we have the following errors coming back potentially from the OS (from the "Identity Document Framework", which is provided by the OS/platform):
switch (error.code) {
case WKIdentityDocumentPresentmentErrorNotEntitled:
exceptionData = { ExceptionCode::NotAllowedError, "Not allowed because not entitled."_s };
break;
case WKIdentityDocumentPresentmentErrorInvalidRequest:
exceptionData = { ExceptionCode::TypeError, "Invalid request."_s };
break;
case WKIdentityDocumentPresentmentErrorRequestInProgress:
exceptionData = { ExceptionCode::InvalidStateError, "Request already in progress."_s };
break;
case WKIdentityDocumentPresentmentErrorCancelled:
exceptionData = { ExceptionCode::AbortError, "Request was cancelled."_s };
break;There was a problem hiding this comment.
Apart from the AbortError being discussed in another comment thread, I think it's always the platform that does the credential selection.
Even in WebKit, IIUC, it is the platform that does it.
Maybe we should make it clearer in the text of the algorithm in earlier steps?
I don't know, it might be surprising to some when first hear about the platform here and not sure about its role.
WDYT?
There was a problem hiding this comment.
Yeah, that makes sense. Open to suggestions or can try to clarify things.
There was a problem hiding this comment.
discussed with @mohamedamir ... will switch WKIdentityDocumentPresentmentErrorNotEntitled to NotAllowedError.
For default case where the error is unknown, we should default to "OperationError".
I'll rewrite these in a general form and @mohamedamir will check if they align with Android's platform errors.
| </li> | ||
| <li>If a [=digital credential=] was selected by the user: | ||
| <ol> | ||
| <li>Let |responseData| be a [=string=] [=digital |
There was a problem hiding this comment.
Is this guaranteed to be a string?
should we document this somewhere that this is the expected format?
There was a problem hiding this comment.
I think it has to be a string, as we have to:
- Check if JSON parsable/serializable (otherwise
.toJSON()would break). - Create the JS Object in the right JS realm (which obviously no native app can do for us).
- Check it is a JS Object (because the WebIDL requires it for
.data).
mohamedamir
left a comment
There was a problem hiding this comment.
I like the direction in general, I have added a couple of comments
Thank you, @marcoscaceres
| <li>Present a [=credential chooser=] with |requestData| and wait for the | ||
| user to either: | ||
| <ul> | ||
| <li>Select a [=digital credential=] and [=holder=] that can fulfill | ||
| the request, or | ||
| </li> | ||
| <li>Cancel the operation. | ||
| </li> | ||
| </ul> | ||
| </li> |
There was a problem hiding this comment.
The text below this makes it clear that we might exit the credential chooser due to the abort controller or an error. Those cases should be mentioned here.
There was a problem hiding this comment.
Good point, @jschanck... I'll describe them.
|
Discussed in 21 January 2026 Series B call |
| |document|'s [=relevant settings object=]'s [=environment settings | ||
| object/origin=], and |document|'s [=Document/origin=]. | ||
| </li> | ||
| <li>Present a [=credential chooser=] with |requestData| and wait for the |
There was a problem hiding this comment.
We might need to clarify what happens when there's multiple matching requests or equivalent requests that are valid to present.
d2b7e3f to
53206fd
Compare
|
Discussed on 2026-02-09 call. Editors will bring this back to the group after more research for best practices and to suggest direction. |
| <ul> | ||
| <li>Select a [=digital credential=] and [=holder=] that can fulfill | ||
| the request, or | ||
| </li> |
There was a problem hiding this comment.
Discussed with @mohamedamir, we are going to slot in an issue here for "Presenting with CTAP #456" so it's clear when CTAP comes into play. And we can craft text around the requirements for cross device / cross platform support here of CTAP and potentially the protocols.
note that this is independent of "Mandate one presentation protocol MUST be supported" #454.
| {{AbortSignal}} |signal|: | ||
| </p> | ||
| <ol class="algorithm"> | ||
| <li>Let |requestData| be [=struct=] consisting of |validatedRequests|, |
There was a problem hiding this comment.
Discussed with @mohamedamir and @simoneonofri... I'm going to split this out into two variables, so it's more clear.
In WebKit, this looks like:
struct DigitalCredentialsRequestData {
Vector<ValidatedMobileDocumentRequest> requests;
SecurityOriginData topOrigin;
SecurityOriginData documentOrigin;
};
Adds "present credential requests" algorithm that describes how to present a credential request, including constructing request data, invoking the credential chooser, handling user cancellation, abort signals, platform errors, and processing the selected digital credential.
Closes #???
The following tasks have been completed:
Implementation commitment:
Documentation and checks
Preview | Diff