Search code examples
ruby-on-railsajaxcsrf

Rails authenticity token (CSRF) provided but being refused


I'm sending an AJAX request from my rails site to itself (to go from javascript to a controller). Rails refuses to allow the POST unless I supply an authenticity token, so I added one using

<%= csrf_meta_tags %> 

and

var AUTH_TOKEN = "<%=j form_authenticity_token %>"

and everything was fine. However, a new customer recently installed the plugin that accesses my site and triggers the AJAX in the first place. But for this one customer--the authenticity token was denied, despite being supplied (I checked in the logs.)

I realize I'm not giving a lot of clues to go off of, but what could cause the authenticity token to be accepted in one situation and denied in another? More broadly, how is the authenticity_token generated anyways--a new one every single time the page is loaded?


Solution

  • Rails assigns a cryptographically random CSRF token to the the user session.

    The server compares the value submitted for the authenticity_token parameter to the value associated with the user’s session.

    One thing you especially need to be careful with is that if you are using fragment caching (which speeds up rendering by caching chunks of the view) you need to ensure that your <%= csrf_meta_tags %> are not cached since a stale csrf meta tag will lead to mismatch with the token stored in the session.

    When posting with ajax, you need to forward the CSRF token with the X-CSRF-Token header.

    var promise = $.ajax({ 
        url: '/example',
        type: 'POST',
        beforeSend: function(xhr) { 
            xhr.setRequestHeader('X-CSRF-Token', 
            $('meta[name="csrf-token"]').attr('content')) 
        },
        data: 'someData=' + someData
    });