Rails, Devise authentication, CSRF issue

Jimbo did an awesome job explaining the “why” behind the issue you’re running into. There are two approaches you can take to resolve the issue:

  1. (As recommended by Jimbo) Override Devise::SessionsController to return the new csrf-token:

    class SessionsController < Devise::SessionsController
      def destroy # Assumes only JSON requests
        signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
        render :json => {
            'csrfParam' => request_forgery_protection_token,
            'csrfToken' => form_authenticity_token
        }
      end
    end
    

    And create a success handler for your sign_out request on the client side (likely needs some tweaks based on your setup, e.g. GET vs DELETE):

    signOut: function() {
      var params = {
        dataType: "json",
        type: "GET",
        url: this.urlRoot + "/sign_out.json"
      };
      var self = this;
      return $.ajax(params).done(function(data) {
        self.set("csrf-token", data.csrfToken);
        self.unset("user");
      });
    }
    

    This also assumes you’re including the CSRF token automatically with all AJAX requests with something like this:

    $(document).ajaxSend(function (e, xhr, options) {
      xhr.setRequestHeader("X-CSRF-Token", MyApp.session.get("csrf-token"));
    });
    
  2. Much more simply, if it is appropriate for your application, you can simply override the Devise::SessionsController and override the token check with skip_before_filter :verify_authenticity_token.

Leave a Comment