hotwired / turbo-rails

Use Turbo in your Ruby on Rails app
https://turbo.hotwired.dev
MIT License
2.11k stars 327 forks source link

Redirecting to an external URL from a turbo POST request fails with "blocked by CORS policy" #483

Closed StanBright closed 4 months ago

StanBright commented 1 year ago

Hi guys,

I'm having the following issue:

A simple POST form fails with a "blocked by CORS policy" JavaScript error when there is a redirect to an external URL.

Access to fetch at 'https://www.example.com/' (redirected from 'http://localhost:3000/services') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

To reproduce:

package.json
"@hotwired/turbo": "^7.0.1",
"@hotwired/turbo-rails": "^7.0.1",

Gemfile.lock
turbo-rails (1.4.0)
# Form helper that's used:
= form_with model: @service do |f|

# Controller action:
def create
  redirect_to "https://www.example.com", status: 303, allow_other_host: true
  return
  ...

The request that comes to the server is a "POST request - TURBO_STREAM".

I tried both with @rails/ujs enabled and disabled. The result was the same. The page "hangs", and there's a JavaScript COR policy related error.

I've worked around the issue by disabling turbo from the form (data: { turbo: false }). However, I spent at least two hours reading and experimenting and couldn't make it work with Turbo enabled.

Any ideas what's the right approach to redirect to an external URL when we have a POST request that's a TURBO_STREAM?

enstyled commented 1 year ago

Facing the same situation.

khallouki commented 11 months ago

Has anyone been able to resolve this issue? I am also facing the same issue.

schmijos commented 7 months ago

This can never work and it's by design. The error message you see has nothing to do with Rails' Open Redirect Protection.

The error message is caused by the browser (and not by Rails). Cross-Origin Resource Sharing (CORS) settings are always interpreted by the browser. The redirect will only work if the browser allows it. Today browsers will not redirect you anymore if you initiated a redirect from JavaScript disallowed (or unspecified) by the target.

The conventional solutions I see for this:

brunoprietog commented 4 months ago

Exactly, Turbo must be disabled in those forms or links. Closing because there's nothing we can do to handle this.

woto commented 4 months ago

Take a look at the turbo_power gem. It has ability to redirect after turbo submits the form without necessity to disable turbo rails.

https://github.com/marcoroth/turbo_power-rails?tab=readme-ov-file#turbo-actions

In short controller looks like this:

image

this sent as a response:

<turbo-stream url="https://example.com" turbo-action="advance" action="redirect_to">
    <template></template>
</turbo-stream>

And TurboPower redirects user through JS.

bufordtaylor commented 1 month ago

nothing we can do to handle this.

Literally a package that handles this.

I really think the redirect_to functionality should be included. Quite a common use case.

For those looking for the answer

// application.js
import { Turbo } from "@hotwired/turbo-rails"
Turbo.StreamActions.redirect_to = function () {
  const url = this.getAttribute('url') || '/'
  Turbo.visit(url)
}
# app/helpers/turbo_stream_actions_helper.rb
module TurboStreamActionsHelper
  def redirect_to(url)
    turbo_stream_action_tag :redirect_to, url: url
  end
end

Turbo::Streams::TagBuilder.prepend(TurboStreamActionsHelper)
# in controller
    respond_to do |format|
      format.turbo_stream do
        render turbo_stream: turbo_stream.redirect_to('https://www.example.com')
      end
    end