0

I have a Rails API using Devise and a React frontend. I've made a button that when clicked uses axios to make a DELETE request to the /users/sign_out route (is this how I should be logging out with React & Devise?). When I click the button I get a 404 error on the client, and the below error on the server. It seems like the initial request succeeds, but then it attempts to make another DELETE request to the / route and the user isn't signed out properly. Why is this the case?

Started DELETE "/users/sign_out" for ::1 at 2020-08-04 22:59:19 -0700
Processing by Devise::SessionsController#destroy as HTML
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
Can't verify CSRF token authenticity.
Redirected to http://localhost:3000/
Completed 302 Found in 5ms (ActiveRecord: 0.4ms | Allocations: 2069)


Started DELETE "/" for ::1 at 2020-08-04 22:59:19 -0700
  
ActionController::RoutingError (No route matches [DELETE] "/"):
dya26
  • 37
  • 2
  • 6
  • Have you tried adding preventDefault() after the button press in your JS? https://www.w3schools.com/jsref/event_preventdefault.asp – Mark Allen Aug 06 '20 at 09:16

2 Answers2

1

The issue over here is that the sign_out is actually not working properly. As you can see there is a message in the log regarding Can't verify CSRF token authenticity.. I have a hunch that if you sign out and then try to login without refresh then that wouldn't work either.

To fix this you can take one of these 2 steps:

  1. Override Devise::SessionsController and skip the token check with skip_before_filter :verify_authenticity_token. You should normally see a Completed 204 No Content response on successful sign out.

Be aware, that this would skip the CSRF token check so only do it if you have a different way of authenticating the validity of the request for ex. jwt token

  1. Option would be to just send the CSRF token with your request if you are actually using it.
anonn023432
  • 2,940
  • 6
  • 31
  • 63
  • Skipping the token check has gotten rid of the token authenticity message, but the behaviour in my original post persists. – dya26 Aug 15 '20 at 21:09
0

This issue comes from the respond_to. More precisely, it comes from the method respond_to_on_destroy (Devise::SessionsController#respond_to_on_destroy)

  # Devise::SessionsController
  def respond_to_on_destroy
    # We actually need to hardcode this as Rails default responder doesn't
    # support returning empty response on GET request
    respond_to do |format|
      format.all { head :no_content }
      format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) }
    end
  end

The last line will redirect user to after_sign_out_path while according to the document:

If you are using XHR requests other than GET or POST and redirecting after the request then some browsers will follow the redirect using the original request method. This may lead to undesirable behavior such as a double DELETE. To work around this you can return a 303 See Other status code which will be followed using a GET request.

so I add status: :see_other after redirect_to:

  # Devise::SessionsController
  def respond_to_on_destroy
    # We actually need to hardcode this as Rails default responder doesn't
    # support returning empty response on GET request
    respond_to do |format|
      format.all { head :no_content }
      format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name), status: :see_other }
    end
  end

Which helps me clear the wrong DELETE request.

refs:

  1. Rails Redirect After Delete Using DELETE Instead of GET
  2. How is it possible for a legitimate user to submit an invalid CSRF token in Rails?
fatmylin
  • 21
  • 3