Closed jenshenny closed 1 year ago
Currently my opinion is to see if https://github.com/Shopify/rubygems.org/pull/263 works, and if it does, proceed with that. I have an inkling that it'll hit the same localhost issue though.
Then, I would want to fallback to polling for Safari without entering a device code. It's more susceptible to phishing but it should be fine it we're using it for Safari browsers.
Thanks for investigating! That sounds good to me.
Currently my opinion is to see if Shopify#263 works, and if it does, proceed with that. I have an inkling that it'll hit the same localhost issue though.
Indeed, the modified sockets approach didn’t work on staging.
I would want to fallback to polling for Safari without entering a device code.
We’re intending to move forward with this approach.
We explored the option of serving a fully qualified localhost domain (FQDN) and redirecting from there to bypass Safari's protection of serving mixed content (content from non-https) similar to the strategy mentioned here. However, we also discovered that Spotify had moved away from this approach, although it’s unclear what factors lead to them changing their API. If this is your preferred option, we’d be happy to collaborate but the execution will need to be largely owned by other maintainers since it requires configuring domains.
With the polling solution, we can be self-sufficient and deliver a fix to Safari users more quickly.
I’m happy with fallback to polling 👍🏻 A fallback that depends on distributing a constantly expiring SSL cert strikes me as likely failure-prone over time.
Here are the PRs that adds this in https://github.com/rubygems/rubygems.org/pull/3873 https://github.com/rubygems/rubygems/pull/6774
I'll also update the guides when they are ready to go https://guides.rubygems.org/using-webauthn-mfa-in-command-line/
Is your feature request related to a problem?
The current WebAuthn implementation does not support Safari browsers. This is because Safari blocks any content from localhost servers.
Safari issue trackers: https://bugs.webkit.org/show_bug.cgi?id=186039 https://bugs.webkit.org/show_bug.cgi?id=171934
Other tools
Other CLI tools support interactions with Safari (npm, gh, heroku). Upon a deeper look, they have a similar polling flow.
The send a POST request to a login endpoint to receive an unique link and optionally a unique identifier to avoid phishing (user code)
They poll a certain endpoint with the unique identifier and retrieve the api key/token when the user finishes authenticating on the browser.
npm
Potential Solutions
1. Modified Sockets
Manually redirect to localhost after webauthn verification has been completed.
Prototype 1: Via clicking the localhost link. * simplest solution
https://github.com/rubygems/rubygems.org/assets/42748004/4e2c6af3-22da-4b62-b01a-9b2cad827789
Prototype 2: Browser sending a GET request.
https://github.com/rubygems/rubygems.org/assets/42748004/0656c902-d58c-4a06-a03e-5a2faf76cf95
Branch: https://github.com/Shopify/rubygems.org/pull/263
2. Polling
As with other CLI tools, when requesting a unique url, return a code to use to poll for the otp code upon completion. This would require adding an endpoint to poll and modifying the current API endpoint to return an unique identifier for polling.
If this solution is chosen, should we only poll for Safari? Should we switch to this implementation in the long term?
3. Manual pasting
After browser verification, instead of sending the OTP via socket, display the code for the user to use.
How does the user input the manual code? Have a code prompt in the CLI if safari is their default browser, via the –otp option?