Skip to content
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

User activation et webauthn #1002

Open
asma1402 opened this issue Mar 27, 2023 · 3 comments
Open

User activation et webauthn #1002

asma1402 opened this issue Mar 27, 2023 · 3 comments

Comments

@asma1402
Copy link

Hello,
I'm using SPC for payment, in my application, it doesn't work in some chrome old versions, and on fireFox, i'm trying to implement PaymentRequest with Webauthn to make it work like SPC, and using a fallback payment method for old version that doesn't support PaymentRequest Or Webauthn.
What i did is simple :
After i receive show() response, and before i call the complete methode, I use navigator.credentials.get() to tell the user to give his credentials, and send them to the relying party, if all good i send the PaymentResponse and the creds to the PaymentServer.
everything is working just fine, i have just one issue, if the user takes it's time before he gives his fingerprint or any other webauth credentials, i get this error :

uncaught (in promise) DOMException: Failed to execute 'show' on 'PaymentRequest': PaymentRequest.show() requires either transient user activation or delegated payment request capability

I read about user activation, and i learn't that it's a new feature implemented for security reasons, I guess when the user takes his time to click on webAuthn, the user activation timeout for show() is consumed and this error shows.

I don't know if there is any solution to keep user activation transient, untel the user give his fingerprint.

Thank you.

@stephenmcgruer
Copy link
Collaborator

Hi @asma1402 . Can you clarify the exact ordering of calls here? At first you say (emphasis mine):

After i receive show() response, and before i call the complete methode, I use navigator.credentials.get()

But then you say:

if the user takes it's time before he gives his fingerprint or any other webauth credentials, i get this error : ... Failed to execute 'show' on 'PaymentRequest'

The latter quote sounds like you are calling navigator.credentials.get() first, before calling PaymentRequest.show().

Are you able to post a code snippet showing what your code looks like? (Or even better, a reproduction website!)

@asma1402
Copy link
Author

asma1402 commented Apr 5, 2023

Hi Stephen
I hope you're doing well, the idea is that we want to create something like SPC for browsers that do not support it, but support Payment Request API, we procede in 3 parts :
first the user register if he's not already registred, we call the credentials.create() function for this
second we execute show method with our payment method and ask him to confirm the order
and at last the user should confirm his order by giving a fingerprint, here we call : credentials.get()

the problem we have is that we have one button to do all the work, let's say a "pay" button, when we click on it we will
ask the user to register, so if the user takes a lot of time the show method will not execute and we will have : uncaught (in promise) DOMException: Failed to execute 'show' on 'PaymentRequest': PaymentRequest.show() requires either transient user activation or delegated payment request capability

is there any event that i can listen to to trigger the show method after the credentials.create(), or to keep the user transient for a mutch longer time?
or is there any way we can execute credentials.create() and the show() within the same event ?

// when we click on the pay button async function pay() { const cred = await navigator.credentials.create({ publicKey }); // we fetch the data in a post request in a remote server, and then we will get them back from the server(we are not using a localstorage) const supportedInstruments = [{ supportedMethods: ".....", ...... }]; const details = { id: 'order-123', displayItems: [ { label: "Sub-total", amount: { currency: "EUR", value: "55.00" }, }, ], total: { label: "Total", amount: { currency: "EUR", value: "65.00" }, } }; const options = {requestPayerName: false, requestShipping: false}; const request =new PaymentRequest(supportedInstruments, details, options); const response = await request.show(); // error from here }
@stephenmcgruer

@stephenmcgruer
Copy link
Collaborator

Thanks for the details @asma1402 .

create something like SPC for browsers that do not support it, but support Payment Request API [for our payment method]

Which browsers are you thinking of? To my knowledge:

  1. Chromium-based browsers support SPC, and support Payment Request with custom payment methods (via Payment Handler)
  2. Gecko-based browsers do not support SPC or Payment Request
  3. Safari does not support SPC, and support Payment Request only for the Apple Pay payment method
  4. Other WebKit-based browsers do not support SPC, and (I think) do not support Payment Request.

Returning to your problem:

You are indeed correct that the problem is that if too much time passes between the user click event, and the call to show(), the user activation will time out. And in your case, because you are trying to do a navigator.credentials.create between these two it is quite likely to reach that time out.

There is unfortunately no current fix for what you are trying to do, because user activation cannot stay activated indefinitely as it would otherwise be no protection at all.

However, we (Chrome) are currently considering relaxing the user activation requirement for Payment Request, such that a page might get one 'free' call (without user activation) to show() per page-load. This is still in early stages of consideration, so no promises at all!

In the meantime, I can see two workarounds to your situation:

  1. Could the Payment Handler itself call navigator.credentials.create()? That is, trigger show() first, and then from within the Payment Handler do the credential creation. (Might not be a fix, if your payment method is not the same domain as you are trying to create a credential for).
  2. Have a second 'continue' button after the credential.create() call, and use that click event on that 'continue' to trigger the show() call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants