@webknjaz reported:
@brainwane I've tried that on Test PyPI.
So I have a TOTP set up. I clicked on Add 2FA with security key.
It prompted me to enter a Key name which I did (Yubikey Neo).
After that, clicking Provision key does nothing visually. So I've opened DevTools.
I can see a successful GET request to https://test.pypi.org/manage/account/webauthn-provision/options with some JSON payload in the response. It looks legit, contains my user data and a challenge.
After clicking more times on that button, each of them produces an exception being logged to the JS console.
The same happenes on prod PyPI, in incognito mode, with browser extensions disabled.

Google Chrome
Version 69.0.3497.81 (Official Build) (64-bit)
running Gentoo Linux
[8] bind-modal-keys.js:43 Uncaught (in promise) DOMException: A request is already pending.
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
Promise.then (async)
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
Promise.then (async)
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
Promise.then (async)
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
(anonymous) @ webauthn.js:179
(anonymous) @ webauthn.js:23
r @ runtime.js:55
(anonymous) @ runtime.js:293
t.(anonymous function) @ runtime.js:107
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
d @ raven.js:445
[2] bind-modal-keys.js:43 Uncaught (in promise) DOMException: The operation either timed out or was not allowed. See: https://w3c.github.io/webauthn/#sec-assertion-privacy.
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
Promise.then (async)
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
Promise.then (async)
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
Promise.then (async)
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
(anonymous) @ webauthn.js:179
(anonymous) @ webauthn.js:23
r @ runtime.js:55
(anonymous) @ runtime.js:293
t.(anonymous function) @ runtime.js:107
r @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
(anonymous) @ bind-modal-keys.js:43
d @ raven.js:445
_Originally posted by @webknjaz in https://github.com/pypa/warehouse/issues/5661#issuecomment-503486463_
This version of chrome is fairly out of date. Would it be possible to try with a more recent release of Chrome @webknjaz?
It'll take some time for me to get it, but from what I see it should be a bug on JS side unrelated to a browser.
[2] bind-modal-keys.js:43 Uncaught (in promise) DOMException: The operation either timed out or was not allowed. See: https://w3c.github.io/webauthn/#sec-assertion-privacy.
specifically this log line makes it appear that it's not an issue with JS served by warehouse, but rather on the browser side, as the attestation never completed.
WebAuthn requires browser implementations to "play nicely", and in this case it appears the browser did not ever respond.
Was there a pop over requesting access to the token?
Right. No pop-up. I've just tried on a PixelBook (Chrome 75, ChromeOS==fancy Gentoo) and a pop-up appears there.
Interestingly, I'm able to use my Yubikey with GitHub which probably means that they work around the standard...
/me navigates to the Google Chrome changelog for more details
This suggests that they've added some webauthn support in Chrome 67: https://developers.google.com/web/updates/2018/05/webauthn
So it seems like the better support for Webauthn was introduced around January. It probably makes sense to put a big red warning next to the 2FA setting if the browser is old...
So what's the minimum Chrome version that properly supports WebAuthn, including PublicKeyCredential and any other components we need? Clearly Version 69 didn't, even though there was some WebAuthn support as of Version 67.
https://webauthn.guide/ states this:
As of January 2019, WebAuthn is supported on Chrome, Firefox, and Edge, with upcoming support on Safari.
So probably matching release dates should give proper versions.
There was a stable release of Chrome 72 in Jan 2019. If some wants to, they can investigate to see if this information is available on Google's Chrome Releases blog:
I think this may hit non-Chrome users as well.
They might have changed it since I last checked, but I believe GitHub doesn't actually use WebAuthn for security keys yet -- I believe they're still on U2F via u2f.js. That would explain why they aren't affected.
Chrome 74 on macOS works for me, as does FF latest on macOS. At the risk of speculating idly, maybe it's a CTAP issue with Linux + Chrome? I vaguely remember having to add udev rules when I added my security keys on Linux, so maybe there's other mis-interacting components there. I'll do some testing on my Linux machines this evening.
Nah, that's def on the browser side ;)
Google Accounts uses webauthn for login, but not registration.
Just confirmed that it works on Chrom(e|ium) 75 (Ubuntu 18.04).
Chrome 67 was released in May 2018 and WebAuthn Level 1 wasn't formally released until March of this year, so it's entirely possible that we're seeing either the effects of a spec change or just a buggy early implementation. Perusing through the chromium issue tracker, I think the latter is a safe bet.
Either way, it'd be interesting to see what exactly is failing. @webknjaz, would you be able to run a local deployment and insert some catches + logging?
Do you mean that I'd need to run it with a front-end build in dev mode with src-maps?
I don't have warehouse locally, but if needed I can find some time and set up the dev env. It may be faster for you to run some Ubuntu VM from vagrant locally with an old Chrome installed there...
Hey, sorry for the late response. You shouldn't need the source maps, it should be sufficient to just pepper some .catch(...) calls on the promises and see what the actual exception is.
Can I just stick some breakpoints in DevTools then?
Yep, that should also work.
I mean, I should be able to do this in the prod PyPI, right?
Ah, yes. Nothing should be different in prod.
That's better! Because I cannot find time to spin up everything locally right now :)
I thought that maybe it's minimized there.
Hm... It's minified and my browser doesn't pick up srcmaps for some reason.
This should be resolved, there was a misconfiguration on test.pypi.org that was not present on pypi.org.
Can you attempt to reproduce and update us if it is still not working?
Hm... Setting breakpoints in https://github.com/pypa/warehouse/blob/0d9c726/warehouse/static/js/warehouse/utils/bind-modal-keys.js#L43 doesn't work for me.
I was able to set some breakpoints but no success figuring out where the exception happens. Only that it's in some promise...
So I set up a local instance. I commented out the whole bind-modal-keys.js but the exception logged in the console still points to that file, to one of the commented lines.
I think that maybe srcmaps aren't generated properly...
I have a feeling that some promise hasn't been awaited.
I believe that one of the problems is that func(csrfToken) @ https://github.com/pypa/warehouse/blob/0d9c726153394cf6aca178c9015c467707fbaa2e/warehouse/static/js/warehouse/utils/webauthn.js#L47 isn't awaited. But there's more.
After doing some debugging with @webknjaz, I noticed that I can reproduce this exception in modern Chrome as well by simply clicking "Provision key" and then canceling the in-browser modal that appears, so it seems like there's two issues here:
After further debugging, I've found out that if (!window.PublicKeyCredential) { feature detection check is invalid. This function is present in my version of Chrome, that's why I don't get any error messages displayed (the DOM node stays hidden).
https://github.com/pypa/warehouse/blob/1d8e0fa/warehouse/static/js/warehouse/utils/webauthn.js#L163
So I've tried https://demo.yubico.com/u2f and https://demo.yubico.com/webauthn .
The first one works and the second works partially. There's an "Internal authenticator" test which doesn't work.
pics


So does Warehouse only implement this internal authenticator type support?
I've noticed there's u2f.getApiVersion() method available. Here's the version in my browser:
> u2f.getApiVersion(console.log)
{js_api_version: 1.1}
If modern browsers have a different one — maybe that's it?
Also, this article https://www.ubisecure.com/api/fido-webauthn-api/ suggests using PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() for the feature discovery:
The isUserVerifyingPlatformAuthententicator method can be used to detect if a platform authenticator that implements user verification exists on the user’s device. This allows the application to improve user experience by only displaying options in the user interface that are sure to exist.
Here's the output for me:
> PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then(console.log)
Promise {<pending>}
false
I probably nailed it. Needs testing tho. On the platforms, I don't have. #6264.
I probably nailed it.
Wrong guess...
@webknjaz Can you attempt to repro on master (which should also be live)? #6305 may have fixed this.
@woodruffw So I've tried it out locally. Nothing happens on the first click. But when I click [ Set up security device ] for the second time, A request is already pending. error message appears. When I click more, every subsequent click adds another instance of that error message.
            
Contractors on the OTF-funded work need to stop work on the security features in order to ensure we complete the accessibility and internationalization work by the end of the month. Therefore, while this is necessary to get us out of beta for this feature https://github.com/pypa/warehouse/issues/5661#issuecomment-515802931 , I'm removing it from the milestone.
@woodruffw did you mean to also close this?
Yes! Thanks @webknjaz.