10

here my problem,

I've got a rails 3.1 app and I'm trying to make an ajax request but I get the warning message "WARNING: Can't verify CSRF token authenticity"…

Inside my layout I've got the helper method "csrf_method_tag", and I add the following javascript code (don't know if it's really required or not):

$.ajaxSetup({
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
  }
});

My Gemfile contains the gem jquery-rails (>= 1.0.12) and I require jquery & jquery-ujs at the top of my application.js.

Even with that, the message still appears. Did i forget something?

Thanks for you help.

K'ao
  • 330
  • 1
  • 3
  • 13
  • having the same problem - and after login I get logged out if I change pages (using devise and rpx connectable gems). Let us know if you solve this – Plattsy Sep 06 '11 at 01:20
  • Is the same cookie being sent in the headers on the AJAX request as was sent on the request that loaded the page that makes the request? The CSRF token is validated in symphony with the current session, which is maintained in another header (which should be sent automatically but might not be in your case). – Steven Sep 09 '11 at 18:21
  • Look at my answer here: http://stackoverflow.com/questions/15239818/iframe-causes-cant-verify-csrf-token-authenticity-n-rails/15869772#15869772 – tinker Apr 08 '13 at 01:22

7 Answers7

9

I had this exact same trouble. I was trying to catch a javascript event (you_tube player completed) and Ajax back to my server to let me know. I was getting:

WARNING: Can't verify CSRF token authenticity

whenever the jQuery ajax call hit my server. I added your code fix above

$.ajaxSetup({
    beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRF-Token',
                             $('meta[name="csrf-token"]').attr('content'));
    }
});

and it works fine. I think the only difference is in my layout I have

<%= csrf_meta_tags %>

and not csrf_method_tag as you mentioned in your original post.
So thank you for the fix, it was in the original post.

Alba Mendez
  • 4,432
  • 1
  • 39
  • 55
Mike Vargo
  • 91
  • 1
  • 2
    **Please _don’t_ use signatures or taglines in your posts.** Read [the FAQ entry](http://stackoverflow.com/faq#signatures) for more info. Thanks! – Alba Mendez Oct 23 '11 at 14:37
7

You probably don't even need this in your code. The jquery-rails gem automatically sets the CSRF token on all Ajax requests by default.

Dylan Markow
  • 123,080
  • 26
  • 284
  • 201
7

What's worked for me - when working without forms - is to include the result of <%= form_authenticity_token %> in the ajax data payload. So I do something like what was suggested by tehprofessor in the html:

<input id="tokentag" type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" />

then in the javascript:

tokentag = $('#tokentag').val()
submitdata = { "authenticity_token": tokentag, ...+whatever else you need to include+...}

then call the $.ajax with submitdata.

Benoit Garret
  • 14,027
  • 4
  • 59
  • 64
techyak
  • 86
  • 1
1

Just do it directly on your AJAX call and it will work right!

  $.ajax({
            type: //method,
            beforeSend: function(xhr){
                xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
            },
            url: //parameter,
            dataType: 'html',
            success: function(data, textStatus, jqXHR) {
               // some code
            }
  });
Ezequiel
  • 13
  • 2
0

The problem is that you need to fetch a new token after an Ajax POST request because once a token is used it gets invalidated. Here is the code to do this:

In rails whenever a POST reply is sent add these parameters to the response:

def someMethod:
    result[:csrfParam] = request_forgery_protection_token
    result[:csrfToken] = form_authenticity_token
    render :json => result
end

Now on the JS side, in the success function of every POST method you can call this function:

var setCsrfToken = function(param, token) {
    if(param == null || token == null) {
        console.error("New CSRF param/token not present");
    }
    $("input[name='" + param + "']").val(token);
}

like this:

setCsrfToken(result["csrfParam"], result["csrfToken"]);

This function will reset all authenticity_token params in all POST forms so that the next request has a valid token. You need to make sure this happens in every POST call, otherwise you'll continue facing this problem.

Also, CSRF is not for preventing clickjacking, it's a separate attack altogether, where another website can make a user click a link that executes an action on your website with the user's session.

tinker
  • 1,396
  • 11
  • 20
0

Have you tried using a hidden form element with authenticity token?

<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token>" />

I was having the same error, and that resolved it. It was because I wasn't using the built in form helpers...

tehprofessor
  • 2,957
  • 1
  • 21
  • 22
  • Nope, still doesn't work… I have to fix this issue before the end of the week, I let you know if I find something… – K'ao Sep 20 '11 at 08:50
0

One reason may be that you make AJAX call before document loaded, so JQuery can't get CSRF token.

fatihpense
  • 618
  • 9
  • 11