devise_token_auth icon indicating copy to clipboard operation
devise_token_auth copied to clipboard

Unsafe redirect on signup [Rails 7.0]

Open urbanrotnik opened this issue 2 years ago • 5 comments

  • Version:
ruby '3.1.2'
gem 'devise_token_auth', git: 'https://github.com/lynndylanhurley/devise_token_auth.git', ref: '798255ee7e3fee5cfa2fdc519fd90e281bd9b6f5'
gem 'rails', '~> 7.0.3'

I am getting an UnsafeRedirectError at:

ActionController::Redirecting::UnsafeRedirectError: Unsafe redirect to "https://example.com/signup?auth_token=myAuthToken&blank=true&client_id=ClientID...", pass allow_other_host: true to redirect anyway.
File "/app/vendor/bundle/ruby/3.1.0/gems/actionpack-7.0.3/lib/action_controller/metal/redirecting.rb" line 193 in _enforce_open_redirect_protection
File "/app/vendor/bundle/ruby/3.1.0/gems/actionpack-7.0.3/lib/action_controller/metal/redirecting.rb" line 89 in redirect_to
File "/app/vendor/bundle/ruby/3.1.0/gems/actionpack-7.0.3/lib/action_controller/metal/instrumentation.rb" line 42 in block in redirect_to
File "/app/vendor/bundle/ruby/3.1.0/gems/activesupport-7.0.3/lib/active_support/notifications.rb" line 206 in block in instrument
File "/app/vendor/bundle/ruby/3.1.0/gems/activesupport-7.0.3/lib/active_support/notifications/instrumenter.rb" line 24 in instrument
File "/app/vendor/bundle/ruby/3.1.0/gems/activesupport-7.0.3/lib/active_support/notifications.rb" line 206 in instrument
File "/app/vendor/bundle/ruby/3.1.0/gems/actionpack-7.0.3/lib/action_controller/metal/instrumentation.rb" line 41 in redirect_to
File "/app/vendor/bundle/ruby/3.1.0/bundler/gems/devise_token_auth-798255ee7e3f/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb" line 232 in render_data_or_redirect
File "/app/vendor/bundle/ruby/3.1.0/bundler/gems/devise_token_auth-798255ee7e3f/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb" line 73 in omniauth_success

Adding config.action_controller.raise_on_open_redirects = false to applcation.rb would help, but redirect should be fixed I think.

urbanrotnik avatar Jun 01 '22 14:06 urbanrotnik

@urbanrotnik I ran into the same issue. A quick workaround is to do a double redirect. Provide a same-host url to devise_token_auth that will route to one of your controller actions and you can route to whatever url you want. But now it's in your control.

muyiwaoyeniyi avatar Feb 03 '23 14:02 muyiwaoyeniyi

@muyiwaoyeniyi could you share the changes you've done step by step 🙏 I know parameters should be passed but I'm confused enough trying to get the whole flow to work...

malopez16 avatar Feb 09 '23 01:02 malopez16

@malopez16 I can't put together a code snippet at the moment. This issue is happening because you're redirecting to a domain different from your server's domain. So here's what I did... set the redirect_url to a route on your server, then in the controller action for the route, you can redirect to the original/final url but add the allow_other_host flag... so

redirect_to FINAL_URL, allow_other_host: true

This goal here is to get devise token auth to redirect to a safe url (controller action) that is within your control and then from there you can redirect wherever you want.

muyiwaoyeniyi avatar Feb 09 '23 03:02 muyiwaoyeniyi

Exactly, we monkey-patch device_token_auth as follow to add allow_other_host: true Disclaimer: it's a quick and dirty solution.

config/initializers/devise_token_auth_monkey_patching.rb

Rails.configuration.to_prepare do
  DeviseTokenAuth::ConfirmationsController.class_eval do
    def show
      @resource = resource_class.confirm_by_token resource_params[:confirmation_token]

      if @resource.errors.empty?
        yield @resource if block_given?

        redirect_header_options = {account_confirmation_success: true}

        if signed_in? resource_name
          token = signed_in_resource.create_token
          signed_in_resource.save!

          redirect_headers = build_redirect_headers(token.token,
                                                    token.client,
                                                    redirect_header_options)

          redirect_to_link = signed_in_resource.build_auth_url redirect_url, redirect_headers
        else
          redirect_to_link = DeviseTokenAuth::Url.generate redirect_url, redirect_header_options
        end

        redirect_to redirect_to_link, allow_other_host: true
      else
        redirect_to DeviseTokenAuth::Url.generate(redirect_url, account_confirmation_success: false), allow_other_host: true
      end
    end
  end
end

micred avatar Feb 09 '23 14:02 micred

I was having this same problem for the password reset flow. In my case, I just had to add allow_other_host: true in my passwords controller, as the default redirect in the DeviseTokenAuth::PasswordsController has a redirect_options hash. Not sure why the confirmations controller doesnt

class Auth::PasswordsController < DeviseTokenAuth::PasswordsController

  private
    def resource_params
      params.permit(:email, :reset_password_token, :config, :redirect_url)
    end

    def redirect_options
      {
        allow_other_host: true
      }
    end

end

GMolini avatar Jun 15 '23 14:06 GMolini