Proper way to send an Authenticity Token with AJAX to Rails
Solution 1
Actually, you are reading the action
attribute of form and sending a post ajax request to it. to send form data you have to submit the form or you can serialize the form data and send it in ajax request like
$(".ajax-referral").click(function(){
$.ajax({
type: "POST",
url: $(this).parent("form").attr("action") + "?&authenticity_token=" + AUTH_TOKEN,
data:$(this).parent("form").serialize(),
dataType: "script"
});
return false;
});
Doing this will serialize your form data and send it along with ajax request and authenticity token is already being sent via query string
Solution 2
This token also already appears in one of the "meta" tags in the head of the application.html.erb layout file by default if you have the following ERB at the top:
<%= csrf_meta_tag %>
That ERB roughly renders to:
<meta content="abc123blahblahauthenticitytoken" name="csrf-token">
You can then grab it using jQuery with the following code:
var AUTH_TOKEN = $('meta[name=csrf-token]').attr('content');
Solution 3
None of these worked for me until I set the X-CSRF-Token
value on the request header via JS like this:
request.setRequestHeader('X-CSRF-Token', token)
token
of course, being the CSRF token. I got this from the <meta name="csrf-token">
tag and did not use encodeURIComponent()
Update since this is proving useful to some
So all in all:
var token = document.querySelector('meta[name="csrf-token"]').content
request.setRequestHeader('X-CSRF-Token', token)
Solution 4
Thanks!
Just to clarify for the more common use.
You need the js tag with var AUTH_TOKEN in your head. Should be something like this.
<%= csrf_meta_tag %>
<%= javascript_tag "var AUTH_TOKEN = '#{form_authenticity_token}';" if protect_against_forgery? %>
And then simply put your authenticity_token=AUTH_TOKEN in the ajax data if you don't need to use parent(form) or something like this.
$.ajax({
type: 'post',
dataType:'text',
data: "user_id="+user_id+"&authenticity_token="+AUTH_TOKEN,
url:'/follow/unfollow'
})
Thanks to the guys above for sharing this knowledge!
Solution 5
In Rails 5.1+ a CSRF token is automatically appended if you use a built-in Rails
JS helper for AJAX requests(from rails-ujs
), example:
Rails.ajax({
url: "/your/url",
type: "POST",
data: "a=1&b=2",
success: function(data) {
console.log(data);
}
});
This library also provides you a helper to get CSRF token manually if you need it with:
Rails.csrfToken();
Trip
I program Ruby, C#, iOS, Node, and Augmented Reality for Unity3D. I write PostgreSQL, mySQL, SQLite, and MongoDB. I use Heroku, Amazon, Microsoft Azure. Creator of the Yoga Sutras App, Braidio Mobile, and Braidio. In my spare time, I teach Ashtanga Yoga. elephant trip AT gmail DOT com #happyToHelp
Updated on July 09, 2022Comments
-
Trip almost 2 years
This works but gets stopped because it lacks an authenticity token:
$(".ajax-referral").click(function(){ $.ajax({type: "POST", url: $(this).parent("form").attr("action"), dataType: "script"}); return false; });
So I tried adding it like so:
$(".ajax-referral").click(function(){ $.ajax({type: "POST", url: $(this).parent("form").attr("action") + "?&authenticity_token=" + AUTH_TOKEN, dataType: "script"}); return false; });
And it passes the auth_token correctly as a param, but seems to lose the rest of my form.
Anyways to accomplish both sending the form data that works, and the authenticity token as well?
This is a rails environment. And I have this in my head.
= javascript_tag "var AUTH_TOKEN = '#{form_authenticity_token}';" if protect_against_forgery?
Things I've tried
1.
= hidden_field :authenticity_token, :value => form_authenticity_token
2.
$.ajax({type: "POST", url: $(this).parent("form").attr("action"), dataType: "script", authenticity_token: AUTH_TOKEN});
3.
// Always send the authenticity_token with ajax $(document).ajaxSend(function(event, request, settings) { if ( settings.type != 'GET' ) { settings.data = (settings.data ? settings.data + "&" : "") + "authenticity_token=" + encodeURIComponent( AUTH_TOKEN ); } });
-
Ken over 9 yearsI had to use encodeURIComponent( AUTH_TOKEN ), but using it in the query string worked once I did this.
-
Bryan Larsen over 9 years
<input type="hidden" name="authenticity_token" value={$('meta[name=csrf-token]').attr('content')}/>
(Note that I'm using JSX for templating. Replace the{
with whatever's appropriate for your template language. -
iblue almost 8 yearsThe auth token is base64 encoded. It may contain a plus sign (+). If you don't properly escape the auth token, rails will parse it as a space, because of url encoding.
-
Gacci over 6 yearstoken should not be sent in the url!
-
Fabrizio Bertoglio about 5 yearsmay not be possible in rails 5 as each form get his own auth token blog.bigbinary.com/2016/01/11/…
-
omdel about 5 yearsGood point, @FabrizioBertoglio I think this comment was written around Rails 3/Rails 4 days. May not be possible to do it this way in later versions.
-
tadman almost 5 yearsThis is the solution for Rails 5+ with the gotcha that
per_form_csrf_tokens
must be set for Single Page Application situations. -
Julien over 3 years@Gacci unless your endpoint URL is http (i.e. plain-text), the params (
authenticity_token
in this case) will also be encrypted. So I'd rather say "token should always be sent to httpS URLs". Ajax-called URLs are not kept in browser history anyway.