Skip to content

Commit aa157f5

Browse files
authored
FIX: Delete destination_url cookie when it's used to set origin param during redirect to social auth (#36194)
When we navigate out to a social auth method, we set the origin param on that request to the value of the destination_url. Upon returning to Discourse, that origin param is returned and [we use it to set](https://github.com/discourse/discourse/blob/4dd3becec10c5b245ca122e684244f604b5c550a/config/initializers/009-omniauth.rb#L24) server_session["destination_url"]. Then during the [omniauth callback](https://github.com/discourse/discourse/blob/4dd3becec10c5b245ca122e684244f604b5c550a/app/controllers/users/omniauth_callbacks_controller.rb#L43), we use the server_session["destination_url"] value to redirect back to the page the destination_url cookie originally pointed to. The problem is that in this scenario, the destination_url cookie never gets deleted. This was causing a bug with Discourse ID in a corner case where [the discourse-login plugin sets the destination_url cookie](https://github.com/discourse-org/discourse-login/blob/646e32f4a66acab3692360188364815e5ff08fcf/config/initializers/doorkeeper.rb#L38) to a url that contains an OAuth state parameter which can become stale, and the cookie keeps getting re-used for redirection but not deleted, resulting in an error message "Sorry, the authorization timed out, or you have switched browsers. Please try again." which the user can't escape. The solution is to make sure that when we return to the omniauth callback we always clean up both the server_session[:destination_url] and cookies[:destination_url]
1 parent 5789d7e commit aa157f5

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

app/controllers/users/omniauth_callbacks_controller.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,15 @@ def complete
4242
session.delete(:destination_url) # Clean up old values. TODO: Remove after March 2026
4343
if server_session[:destination_url].present?
4444
preferred_origin = server_session[:destination_url]
45-
server_session.delete(:destination_url)
4645
elsif SiteSetting.enable_discourse_connect_provider && payload = cookies.delete(:sso_payload)
4746
preferred_origin = session_sso_provider_url + "?" + payload
4847
elsif cookies[:destination_url].present?
4948
preferred_origin = cookies[:destination_url]
50-
cookies.delete(:destination_url)
5149
end
5250

51+
server_session.delete(:destination_url)
52+
cookies.delete(:destination_url)
53+
5354
if preferred_origin.present?
5455
parsed =
5556
begin

spec/system/social_authentication_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,36 @@
438438
expect(page).to have_css(".header-dropdown-toggle.current-user")
439439
end
440440

441+
it "removes destination_url cookie if present after setting up redirect" do
442+
mock_facebook_auth
443+
visit("/")
444+
445+
category = Fabricate(:category)
446+
447+
signup_page.open
448+
449+
# Manually set the destination_url, as if it were set by a plugin
450+
page.driver.with_playwright_page do |pw_page|
451+
pw_page.context.add_cookies(
452+
[{ url: pw_page.url, name: :destination_url, value: category.url }],
453+
)
454+
455+
cookie_found =
456+
pw_page.context.cookies.any? { |cookie| cookie["name"] == "destination_url" }
457+
expect(cookie_found).not_to be_falsey
458+
end
459+
460+
signup_page.click_social_button("facebook")
461+
expect(page).to have_current_path(category.url)
462+
463+
# Ensure the destination_url cookie was removed after being used
464+
page.driver.with_playwright_page do |pw_page|
465+
cookie_found =
466+
pw_page.context.cookies.any? { |cookie| cookie["name"] == "destination_url" }
467+
expect(cookie_found).to be_falsey
468+
end
469+
end
470+
441471
context "with a suspended user" do
442472
before do
443473
user.suspended_till = 2.years.from_now

0 commit comments

Comments
 (0)