Hotwire rails app: redirect to external service fails

980 views Asked by At

I am integrating discourse single sign on with hotwire rails application, everything works fine till redirection, when it redirects I see there is CORS issue browser, ofcourse its turbo request so it attempts to fetch response from give URL so it throws CORS error, How we can do actual redirection here?.

enter image description here

  def sso
    secret = "572890bb92bbef8c4634c1bf"
    sso = SingleSignOn.parse(request.query_string, secret)
    sso.email = current_user.email # from devise
    sso.name = current_user.name # this is a custom method on the User class
    sso.username = current_user.username # from devise
    sso.external_id = current_user.id # from devise
    sso.sso_secret = secret

    redirect_to sso.to_url("https://xxxxxxxx/session/sso_login")
  end

Edit(1)

<main class="main-content">
  <div class="d-flex justify-content-center">
    <div>
      <div class="mt-48 py-48 px-md-48 px-32 border-radius-lg log-in-card box-shadow-05">
        <h4 class="font-size-24 text-black font-weight-400 mb-0">Member Login</h4>
        <%= form_for(resource, as: resource_name, url: session_path(resource_name), html: {class: 'mt-48'}) do |f| %>
          <div class="form-group mb-0">
            <%= f.label :email, class: "font-weight-500 font-size-14 text-black" %>
            <%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control-lg form-control' %>
          </div>
          <div class="form-group position-relative mt-32">
            <%= f.label :password, class: "font-weight-500 font-size-14 text-black" %>
            <%= f.password_field :password, autocomplete: "current-password", class: 'form-control-lg form-control' %>
            <div class="position-absolute eye-icon"><i class="far fa-eye-slash font-size-14 text-black"></i></div>
          </div>
        <div class="d-flex flex-column align-items-center mt-32">
          <%= f.submit "Login", class: 'btn btn-brand-primary py-12 px-48 text-decoration-none' %>
          <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
            <%= link_to "Forget password?", new_password_path(resource_name), class: 'text-decoration-none text-brand-primary font-weight-600 font-size-14 mt-32' %>
          <% end %>
        </div>
        <% end %>
      </div>
      <div class="d-flex justify-content-center mt-48">
        <span class="text-black font-weight-500 font-size-14 text-decoration-none">Not a member?</span>
        <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
          <%= link_to "Create Account", new_registration_path(resource_name), class: 'text-brand-primary font-weight-600 font-size-14 text-decoration-none ml-8' %>
        <% end %>
      </div>
      <div class="d-flex flex-md-row flex-column align-items-center justify-content-center mt-48 mb-96 pb-md-64">
        <span class="text-black font-weight-500 font-size-14 text-decoration-none">Didn't receive confirmation
          instructions?</span>
        <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
          <%= link_to "Request again", new_user_confirmation_path(resource_name), class: 'text-brand-primary font-weight-600 font-size-14 text-decoration-none ml-8'%>
        <% end %>
      </div>
    </div>
  </div>
</main>
2

There are 2 answers

0
Vishal G On BEST ANSWER

I have used data-turbo="false" in signin form, it will send HTML request to backend because of that when I do redirect it will redirect the whole page. Thanks

https://turbo.hotwire.dev/handbook/drive#disabling-turbo-drive-on-specific-links-or-forms

0
Javier Cestau On

If you don't want to deactivate turbo for a particular action. What I did was create a JS script that reloaded the page

views/shared/_reload_script.html.erb

<script>
    window.location = "<%= redirect_url %>";
 </script>

in the particular controller, I added the render when I needed to redirect

example_controller.rb

    render turbo_stream: turbo_stream.append(
          :reload,
          partial: 'shared/reload_script',
          locals: { redirect_url: 'https://example.com' }
     )

and in the view action or application.html.erb I put the DIV with the reload ID

 <div id="reload"></div>

This is an ok solution if removing turbo stream will be a lot of work. I'm not sure if there is a particular drawback for this approach, but for me it's working fine so far.

So the method reads nicer what I also did was creating a method in the application_controller.rb and move the render there

application_controller.rb


  def turbo_stream_redirect_to(redirect_url)
    render turbo_stream: turbo_stream.append(
      :reload,
      partial: 'shared/reload_script',
      locals: { redirect_url: }
    )
  end

So in your action have to call like this:

 turbo_stream_redirect_to 'https://example.com'

NOTE: I would not recommend this approach if the users have the ability to change the URL. but as long you (the devs) are the only one that decides the URL is ok