devise icon indicating copy to clipboard operation
devise copied to clipboard

Rails 7: allow redirections to other/external hosts after logout.

Open ammancilla opened this issue 3 years ago • 9 comments

Context

When using different authentication strategies, devise_saml_autheticatable in my case, it's common to redirect the user to an external host after logout.

Rails 7 requires to explicitly pass allow_other_host: true to redirect_to to allow such redirections. Otherwise, an ugly exception is raised.

  • Devise 4.8.1
  • Rails 7.0.1

Expected behaviour.

When using devise with Rails 7 and setting the after_sign_out_path_for to an external host, the user is sucessfully redirected.

Current behaviour.

When using devise with Rails 7 and setting the after_sign_out_path_for to an external host, a ActionController::Redirecting::UnsafeRedirectError is raised.

ammancilla avatar Jan 27 '22 14:01 ammancilla

There are other places than logout that redirect_to would need allow_other_host: true.

For instance, if I'm on me.site.com and load site.com/sign_in, I'll get redirected back to me.site.com which would raise the exception here... https://github.com/heartcombo/devise/blob/v4.8.1/app/controllers/devise_controller.rb#L116

I don't know how many instances like this there are

daslicious avatar Feb 02 '22 22:02 daslicious

There are other places than logout that redirect_to would need allow_other_host: true.

Yes indeed. For instance we need to be able to set it for the registrations_controller: https://github.com/heartcombo/devise/blob/v4.8.1/app/controllers/devise/registrations_controller.rb#L25-L29

kreintjes avatar Mar 14 '22 15:03 kreintjes

Any chance this will be looked into soon? The same issue happens if after_sign_in_path_for is overridden to return an external host. For now I'm making do by overriding Devise::SessionsController#create.

nehagupta93 avatar May 16 '22 12:05 nehagupta93

I'm also having this issue because I want to redirect to an external Stripe checkout page after a user signs up. For now I am overriding the respond_with method:

def respond_with(resource, location: nil)
  if !resource.persisted? || resource.active_for_authentication?
    super
  else
    co_session = Stripe::Checkout::Session.create(...)
    redirect_to co_session.url, allow_other_host: true
  end
end

trueinviso avatar Nov 26 '22 19:11 trueinviso

Seems like the best way to approach this is add a alow_directs_to_other_hosts configuration under Devise.configure, and then use that everywhere redirect_to is currently used.

Should be relatively straightforward I think

seanarnold avatar Dec 06 '22 03:12 seanarnold

+1 on improvements here, my login broke after a Rails 7 upgrade because I am routing users to a per-user custom external URLs in after_sign_in_path_for

richardonrails avatar Dec 09 '22 16:12 richardonrails

+1 to improvements here, for now we will have to set this new config to false to have our app to still work with devise.

sealabcore avatar Dec 13 '22 22:12 sealabcore

+1 Haven't found another way than setting action_controller.raise_on_open_redirects = false, more than a year later

fonji avatar May 02 '23 09:05 fonji

I just ran in to this problem in project and fixed it across the entirety of devise with

class DeviseController
  # monkey patching devise so it can handle the new default behaviour in rails 7
  #   redirects

  original_redirect_to = instance_method(:redirect_to)
  define_method(:redirect_to) do |options, response_options = {}|
    if options.is_a?(Hash)
      options[:allow_other_host] = true unless options.key?(:allow_other_host)

    elsif response_options.is_a?(Hash)
      response_options[:allow_other_host] = true unless response_options.key?(:allow_other_host)
    end

    original_redirect_to
      .bind_call(self, options, response_options)
  end
end

But please can this be fixed properly?

ivan-kocienski-gfsc avatar Jan 17 '24 09:01 ivan-kocienski-gfsc