Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to get jQuery to work with Rail's Authenticity Token (protect_from_forgery)
<!DOCTYPE html>
<html>
<head>
<title>My Rails App</title>
<%- if protect_against_forgery? -%>
<meta name="authenticity-token" id="authenticity-token" content="<%= form_authenticity_token %>" />
<%- end -%>
<%= javascript_include_tag 'jquery', 'rails' %>
</head>
<body>
<h1>Using jQuery with Rails' Authenticity Token</h1>
<p>
By putting the authenticity token in the head, we can easily grab it from JS.
</p>
</body>
</html>
(function($) {
$.ajaxSettings.accepts.html = $.ajaxSettings.accepts.script;
$.authenticityToken = function() {
return $('#authenticity-token').attr('content');
};
$(document).ajaxSend(function(event, request, settings) {
if (settings.type == 'post') {
settings.data = (settings.data ? settings.data + "&" : "")
+ "authenticity_token=" + encodeURIComponent($.authenticityToken());
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
});
})(jQuery);
@codesoda

This comment has been minimized.

Copy link

@codesoda codesoda commented Nov 16, 2016

A current and simpler way to do this...

$(function(){
  // always pass csrf tokens on ajax calls
  $.ajaxSetup({
    headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }
  });
});
@Metaphysiker

This comment has been minimized.

Copy link

@Metaphysiker Metaphysiker commented Apr 5, 2018

This doesn't work for me.

  1. I added jqueryauthenticity.js to app/assetsjavascripts

  2. I added code to jqueryauthenticity.js

#  jqueryauthenticity.js
$(function(){
  // always pass csrf tokens on ajax calls
  $.ajaxSetup({
    headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }
  });
});
  1. I added //= require jqueryauthenticity to application.js
#application.js
//= require rails-ujs
//= require turbolinks
//= require clipboard
//= require clipboardtooltip
//= require jqueryauthenticity
//= require_tree .

Where did I go wrong?

(I'm using a CDN for jQuery, does this matter?)

@brendon

This comment has been minimized.

Copy link

@brendon brendon commented Jun 20, 2019

This works well:

$.ajaxPrefilter(function(options, originalOptions, xhr) {
  if (!options.crossDomain) {
    token = $('meta[name="csrf-token"]').attr('content');
    if (token) xhr.setRequestHeader('X-CSRF-Token', token);
  }
});

It's basically exactly what jquery-ujs does. No need to wrap it in a $(function(){});

@benlieb

This comment has been minimized.

Copy link

@benlieb benlieb commented Apr 5, 2020

I had an awful time getting this to work, but ATM I'm on the "bleeding edge" and seeing the blood, using Rails 6, webpacker, React. The problem I was having was a combination of load order and the actual instance of jQuery being used inside of @rails/ujs (and also tried jquery-ujs). None of them worked for me.

I was trying to make $ available from inside my environment.js file... By the time the $ was made available inside my react components, it was no longer the same instance as what was used in the ujs files, so the config didn't "take".

My final "solution" that allowed my authenticity token to be sent properly from $.ajax in my react components was to import a "configured" $ manually like this:

utils/jquery.js:

import $ from 'jquery'

$(function(){
  // always pass csrf tokens on ajax calls
  $.ajaxSetup({
    headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }
  });
});

export default $

And inside React component:

import $ from '../utils/jquery'

I'm far from convinced that this is the best way to do this, but after several wasted hours, I'm just happy to have ANY way that works. I'm leaving this up in case it's either helpful for someone else, or someone knows a better way to get this working...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment