Skip to content

Conversation

@segiddins
Copy link
Contributor

@segiddins segiddins commented Dec 14, 2023

What was the end-user or developer problem that led to this PR?

Accessing the webauthn verification link is difficult if you use your phone for your passkeys

What is your fix for the problem, implemented in this PR?

Use vendored rqrcode_code lib to generate a QR code for the link, which is printed out when the output is a tty

image

Make sure the following tasks are checked

@ioquatix
Copy link
Member

This is brilliant.

@segiddins segiddins force-pushed the segiddins/print-qr-code-for-webauthn-verification-link branch 2 times, most recently from 5bbcce7 to a5ecbd6 Compare December 14, 2023 11:44
@segiddins segiddins force-pushed the segiddins/print-qr-code-for-webauthn-verification-link branch 4 times, most recently from 62f3ca7 to 18e973e Compare January 13, 2024 06:52
@deivid-rodriguez
Copy link
Contributor

@segiddins I'm not sure I have the knowledge to review this, but I can try to get up to speed if needed. The vendoring looks fine to me, though!

One thing that immediately comes to mind though is, should the information before the QR code be updated to give a bit of context about the QR code? Maybe:

You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the --otp [your_code] option.

@segiddins
Copy link
Contributor Author

That's a good idea!

@simi
Copy link
Contributor

simi commented Feb 25, 2024

@segiddins any plan to update this PR?

@segiddins
Copy link
Contributor Author

Yes, I will circle back here

@segiddins segiddins force-pushed the segiddins/print-qr-code-for-webauthn-verification-link branch from 18e973e to ae78666 Compare October 4, 2024 18:15
Signed-off-by: Samuel Giddins <[email protected]>
@segiddins segiddins force-pushed the segiddins/print-qr-code-for-webauthn-verification-link branch from ae78666 to 8e81034 Compare October 4, 2024 18:29
@segiddins
Copy link
Contributor Author

@deivid-rodriguez this is now passing with a rebase and the updated message -- let's get it in for 3.6?

@deivid-rodriguez
Copy link
Contributor

@simi Did you plan to review this? I'm not sure I can review the implementation but I'm happy to give the feature a try.

@deivid-rodriguez
Copy link
Contributor

Also happy to ship it for 3.6, yeah!

@deivid-rodriguez
Copy link
Contributor

I tried this and it works fine 🎉. I can open the URL on my phone by scanning the code. My main concern is that it makes the output very noisy when I believe most people is not going to use it. Maybe render the QR when given a --qr flag, similar to --otp?

@segiddins
Copy link
Contributor Author

This is only printed when the account has webauthn enabled, and is spinning up the web server, so I personally would err on the side of showing it, otherwise i worry the improved UX won't be discoverable.

@deivid-rodriguez
Copy link
Contributor

deivid-rodriguez commented Nov 6, 2024

I mean, most webauthn users would open the URL and won't care about the QR? At least I have to say I will myself find this noisy. I was thinking of a similar suggestion to the --otp one we have now, like:

You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the --otp [your_code] option. If you have your passkeys on your phone but not on this machine, you can re-run with the --qr option to get a QR displayed that you can scan, instead of a URL.

@deivid-rodriguez
Copy link
Contributor

I think that would fix the discoverability issue?

@ioquatix
Copy link
Member

ioquatix commented Nov 6, 2024

I'm using webauthn now too, but I still occasionally get prompted for an OTP for some reason.

@deivid-rodriguez
Copy link
Contributor

I haven't seen that since I started using webauthn, it sounds like a bug, right? Does it happen when running gem push or other command?

@deivid-rodriguez
Copy link
Contributor

deivid-rodriguez commented Nov 6, 2024

In any case, that seems unrelated to this PR, since this won't change anything regarding how to choose whether to ask for an explicit OTP code, or use webauthn.

@ioquatix
Copy link
Member

ioquatix commented Nov 6, 2024

On the same machines, about 95% of the time, I get a webauthn link, and about 5% of the time I get an OTP code request.

@deivid-rodriguez
Copy link
Contributor

Is that when running gem push or some other command? So I guess you can reproduce "reliably" by running gem push a few times (and aborting it when it stops asking for otp or webauthn verification)?

@deivid-rodriguez
Copy link
Contributor

deivid-rodriguez commented Nov 19, 2024

@segiddins Thoughts on my suggestion? I think we may want to evolve it to some configuration since users who use the QR code are likely to want to use it always, and users who don't use it are also likely to never want it, but I feel it's a good start without invasive output that stills give visibility to the new feature.

@segiddins
Copy link
Contributor Author

yeah i guess that makes sense, my personal preference is to have it shown but that's just me :)

@deivid-rodriguez
Copy link
Contributor

Just to make sure I understand, you have your passkeys in your phone and because of this you want the QR always shown because it's handy, or even though you don't use the QR, you still like it always printed?

I can see how always printing it may send a "RubyGems is cool" message, but I do find it a bit overwhelming since I won't be using it.

@ioquatix
Copy link
Member

There were some times when it seemed to reliably ask for an OTP for like an hour or two, on all my computers, and then went back to auth link. To be honest, I'm not sure if there was a clear pattern. Maybe the auth link system was broken or disabled for a few hours?

@deivid-rodriguez
Copy link
Contributor

There were some times when it seemed to reliably ask for an OTP for like an hour or two, on all my computers, and then went back to auth link. To be honest, I'm not sure if there was a clear pattern. Maybe the auth link system was broken or disabled for a few hours?

I guess if the api/v1/webauthn_verification endpoint stops working for whatever reason, then you'd fallback to manual OTP, yeah. In any case, it seems unrelated to this PR.

@deivid-rodriguez
Copy link
Contributor

deivid-rodriguez commented Nov 22, 2024

I just realized that if we add a gem push flag to enable displaying the QR, we don't really need anything else, because in order to make the flag "permanent", you'd just have to add it to your RubyGems configuration, like push: --qr and I think that would work? If that's the case, I don't see any gotchas with that approach.

@deivid-rodriguez
Copy link
Contributor

So my suggestion would be something like this:

diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index 12bfe3a834b..2376d119cad 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -39,6 +39,7 @@ def initialize
     add_proxy_option
     add_key_option
     add_otp_option
+    add_qr_option
     defaults.merge! add: [], remove: []
 
     add_option "-a", "--add NEW_OWNER", "Add an owner by user identifier" do |value, options|
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index 726191377a3..919479f5096 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -37,6 +37,7 @@ def initialize
     add_proxy_option
     add_key_option
     add_otp_option
+    add_qr_option
 
     add_option("--host HOST",
                "Push to another gemcutter-compatible host",
diff --git a/lib/rubygems/commands/signin_command.rb b/lib/rubygems/commands/signin_command.rb
index 0f77908c5bf..3a88eb35163 100644
--- a/lib/rubygems/commands/signin_command.rb
+++ b/lib/rubygems/commands/signin_command.rb
@@ -15,6 +15,7 @@ def initialize
     end
 
     add_otp_option
+    add_qr_option
   end
 
   def description # :nodoc:
diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb
index fbdc262549d..dcc8b3139fd 100644
--- a/lib/rubygems/commands/yank_command.rb
+++ b/lib/rubygems/commands/yank_command.rb
@@ -34,6 +34,7 @@ def initialize
     add_version_option("remove")
     add_platform_option("remove")
     add_otp_option
+    add_qr_option
 
     add_option("--host HOST",
                "Yank from another gemcutter-compatible host",
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index e8b6fdb5032..950026cbe50 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -41,6 +41,16 @@ def add_otp_option
     end
   end
 
+  ##
+  # Add the --qr option
+
+  def add_qr_option
+    add_option("--qr",
+               "Print a QR code for multifactor authentication") do |_value, options|
+      options[:qr] = true
+    end
+  end
+
   ##
   # The API key from the command options or from the user's configuration.
 
@@ -262,10 +272,14 @@ def fetch_otp(credentials)
     options[:otp] = if webauthn_url = webauthn_verification_url(credentials)
       server = TCPServer.new 0
       port = server.addr[1].to_s
-
       url_with_port = "#{webauthn_url}?port=#{port}"
-      say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
-      qrcode Gem::RQRCodeCore::QRCode.new(url_with_port)
+
+      if options[:qr]
+        say "You have enabled multi-factor authentication. Please scan the QR below to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
+        qrcode Gem::RQRCodeCore::QRCode.new(url_with_port)
+      else
+        say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
+      end
 
       threads = [WebauthnListener.listener_thread(host, server), WebauthnPoller.poll_thread(options, host, webauthn_url, credentials)]
       otp_thread = wait_for_otp_thread(*threads)
diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb
index 90dca011b72..56586304081 100644
--- a/test/rubygems/test_gem_commands_owner_command.rb
+++ b/test/rubygems/test_gem_commands_owner_command.rb
@@ -387,7 +387,7 @@ def test_with_webauthn_enabled_success
     end
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
@@ -414,7 +414,7 @@ def test_with_webauthn_enabled_failure
 
     assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
     assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
     assert_match "ERROR:  Security device verification failed: Something went wrong", @stub_ui.error
     refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
@@ -436,7 +436,7 @@ def test_with_webauthn_enabled_success_with_polling
     end
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
       "command with the `--otp [your_code]` option.", @stub_ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
@@ -464,7 +464,7 @@ def test_with_webauthn_enabled_failure_with_polling
 
     assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
     assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
       "command with the `--otp [your_code]` option.", @stub_ui.output
     assert_match "ERROR:  Security device verification failed: The token in the link you used has either expired " \
       "or been used already.", @stub_ui.error
diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb
index d2ead52db6d..97786bdbdb7 100644
--- a/test/rubygems/test_gem_commands_push_command.rb
+++ b/test/rubygems/test_gem_commands_push_command.rb
@@ -478,7 +478,7 @@ def test_with_webauthn_enabled_success
     end
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
@@ -506,7 +506,7 @@ def test_with_webauthn_enabled_failure
 
     assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "ERROR:  Security device verification failed: Something went wrong", @ui.error
     refute_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -528,7 +528,7 @@ def test_with_webauthn_enabled_success_with_polling
     end
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
@@ -554,7 +554,7 @@ def test_with_webauthn_enabled_failure_with_polling
 
     assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
       "command with the `--otp [your_code]` option.", @ui.output
     assert_match "ERROR:  Security device verification failed: The token in the link you used has either expired " \
       "or been used already.", @ui.error
diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb
index ecf8fe9ed18..4615c7f9c0b 100644
--- a/test/rubygems/test_gem_commands_yank_command.rb
+++ b/test/rubygems/test_gem_commands_yank_command.rb
@@ -132,7 +132,7 @@ def test_with_webauthn_enabled_success
 
     assert_match %r{Yanking gem from http://example}, @ui.output
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
@@ -164,7 +164,7 @@ def test_with_webauthn_enabled_failure
     assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
     assert_match %r{Yanking gem from http://example}, @ui.output
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "ERROR:  Security device verification failed: Something went wrong", @ui.error
     refute_match "You are verified with a security device. You may close the browser window.", @ui.output
@@ -190,7 +190,7 @@ def test_with_webauthn_enabled_success_with_polling
 
     assert_match %r{Yanking gem from http://example}, @ui.output
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
@@ -220,7 +220,7 @@ def test_with_webauthn_enabled_failure_with_polling
     assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
     assert_match %r{Yanking gem from http://example}, @ui.output
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
     assert_match "ERROR:  Security device verification failed: The token in the link you used has either expired " \
       "or been used already.", @ui.error
diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb
index e650511eca3..f01f6cb2dfa 100644
--- a/test/rubygems/test_gem_gemcutter_utilities.rb
+++ b/test/rubygems/test_gem_gemcutter_utilities.rb
@@ -222,9 +222,11 @@ def test_sign_in_with_incorrect_otp_code
     assert_equal "111111", @fetcher.last_request["OTP"]
   end
 
-  def test_sign_in_with_webauthn_enabled
+  def test_sign_in_with_webauthn_enabled_and_qr_option
     server = Gem::MockTCPServer.new
 
+    @cmd.options[:qr] = true
+
     @fetcher.respond_with_require_otp
     @fetcher.respond_with_webauthn_url
     TCPServer.stub(:new, server) do
@@ -233,8 +235,8 @@ def test_sign_in_with_webauthn_enabled
       end
     end
 
-    assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+    assert_match "You have enabled multi-factor authentication. Please scan the QR below " \
+      "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
     assert_includes @sign_in_ui.output, <<~QRCODE
       █████████████████████████████████████████████████████
@@ -285,7 +287,7 @@ def test_sign_in_with_webauthn_enabled_with_error
     assert_equal 1, error.exit_code
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
     assert_match "ERROR:  Security device verification failed: Something went wrong", @sign_in_ui.error
     refute_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
@@ -303,7 +305,7 @@ def test_sign_in_with_webauthn_enabled_with_polling
     end
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
     assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
     assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
@@ -322,7 +324,7 @@ def test_sign_in_with_webauthn_enabled_with_polling_failure
     end
 
     assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
-      "to authenticate via security device, or alternatively scan the QR code below. If you can't verify using WebAuthn but have OTP enabled, " \
+      "to authenticate via security device. If you don't have your passkeys in this device, you can re-run the gem signin command with the `--qr` option. If you can't verify using WebAuthn but have OTP enabled, " \
       "you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
     assert_match "ERROR:  Security device verification failed: " \
       "The token in the link you used has either expired or been used already.", @sign_in_ui.error

Also, I finally managed to test the whole workflow here and, while it actually worked, I got the following screen after visiting the verification URL which I was not expecting:

Captura de pantalla 2024-12-06 a las 19 03 55

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

Successfully merging this pull request may close these issues.

4 participants