1

A CSRF token error (Can't verify CSRF token authenticity.) will occur if Post transmission is performed on the transition page using turbolinks.

But, when reloading the page, no error occurs.

How can I solve it?


Mr.Mark

Thank you for answering.

Is it due to the fact that the csrf-token of the header is different from the csrf-token of the form?

Why is csrf-token different when using turbolink?

I solved it in the following way, but what do you think?

$(document).on('turbolinks:load', function() {
  token = $("meta[name='csrf-token']").attr("content"); 
  $("input[name='authenticity_token']").val(token)
});

3 Answers3

3

I know this is a year old question but this might help someone in need.

The problem here is the csrf-token in meta tag is different from authenticity_token in the form. I believe turbolinks could be the culprit here.

The solution that worked for me is:

$(document).on('turbolinks:load', function(){ $.rails.refreshCSRFTokens(); });

You will need rails-ujs or jquery-ujs included with your app. If you're on Rails 6, I believe you already have rails-ujs by default.

Abhilash Reddy
  • 1,499
  • 1
  • 12
  • 24
  • This answer will only work with `jquery-ujs`. `rails-ujs` does not define `$.rails` for the obvious reason that it removes the jQuery dependency. It uses the global `Rails`. – max Dec 12 '22 at 11:17
1

This is a popular question the last few days...

I'd suggest following:

WARNING: Can't verify CSRF token authenticity rails

Make sure that you have <%= csrf_meta_tag %> in your layout

Add beforeSend to all the ajax request to set the header like below:

$.ajax({ url: 'YOUR URL HERE',
  type: 'POST',
  beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

To send token in all requests you can use:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});
Community
  • 1
  • 1
Mark
  • 6,112
  • 4
  • 21
  • 46
1

Rails is expecting the form authenticity_token but the CSRF token from the meta tag is being sent instead because you are POSTing a form with any of this options on the Rails form helper:

  • turbo: false
  • local: true
  • remote: false

I solved it by copying the authenticity token from the meta tag, to the form before submitting the form:

// application.js
function copyCSRFMetaTagToFormAuthenticityToken() {
    document.querySelector('input[name="authenticity_token"]').value = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
}
window.copyCSRFMetaTagToFormAuthenticityToken = copyCSRFMetaTagToFormAuthenticityToken

Then in my template:

<%= form_with(url: save_custom_connection_path, method: :post, data: { turbo: false }, :html => { :onsubmit => "window.copyCSRFMetaTagToFormAuthenticityToken()" }) do |form| %>

Notice:

:onsubmit => "window.copyCSRFMetaTagToFormAuthenticityToken()" 

I believe this does not represent any security risk because it's using the view's CSRF token anyway.

Arturo
  • 1,123
  • 3
  • 19
  • 33