lokhi
lokhi

Reputation: 177

Rails Can't verify CSRF token authenticity ajax with X-CSRF-TOKEN header

I try to register a service worker endpoint in my database but when I send my post data with fetch the app raise an error.

I want to keep the csrf verification. Do you see something wrong ?

            var ready;

            ready = function(){
              if ('serviceWorker' in navigator) {
               console.log('Service Worker is supported');
                navigator.serviceWorker.register('/service-worker.js').then(function(reg) {

                 reg.pushManager.subscribe({
                     userVisibleOnly: true
                 }).then(function(sub) {
                     console.log('endpoint:', sub.endpoint);
                     console.log(sub);
                     var token = $('meta[name=csrf-token]').attr('content')
            console.log(token);

                     return fetch('/register_endpoint', {
                    method: 'post',
                    headers: {
                      'Content-type': 'application/json',
                      'X-CSRF-TOKEN': token
                    },
                    body: JSON.stringify({
                      endpoint: sub.endpoint,
                      authenticity_token: token

                    })
                  });
                 });


               }).catch(function(err) {
                 console.log('Erreur -> ', err);
               });
              }

            };



            $(document).ready(ready);
            $(document).on('page:load',ready);

thanks

Upvotes: 2

Views: 3662

Answers (3)

7urkm3n
7urkm3n

Reputation: 6311

$ajax or fetch Both works in your case.

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

$.ajax({ url: URL,
  type: 'POST',
  beforeSend: token,
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

Or:

return fetch( URL, {
 method: 'post',
 headers: {
  'Content-type': 'application/json',
  'X-CSRF-TOKEN': token
  },
  body: JSON.stringify({endpoint: sub.endpoint}),
  credentials: 'same-origin'
})

Upvotes: 0

Omar Rayward
Omar Rayward

Reputation: 481

The problem is that the session cookie is not being sent if credentials is not specified as an option within fetch.

credentials has 3 possible values:

  • omit -> Doesn't send cookies
  • same-origin -> Only send cookies if the URL is on the same origin as the calling script
  • include -> Always send cookies, even for cross-origin calls

So this should probably work:

return fetch('/register_endpoint', {
 method: 'post',
 headers: {
  'Content-type': 'application/json',
  'X-CSRF-TOKEN': token
  },
  body: JSON.stringify({endpoint: sub.endpoint}),
  credentials: 'same-origin'
})

Here more info about the native fetch api.

Upvotes: 10

Kaushlendra Tomar
Kaushlendra Tomar

Reputation: 1440

This is also not working for me so I have override this verified_request? method CsrfToken

class ApplicationController < ActionController::Base
  protect_from_forgery
  skip_before_action :verify_authenticity_token, if: :verified_request?

  protected

  def verified_request?
      return true if request.get?
      if respond_to?(:valid_authenticity_token?, true)
        super || valid_authenticity_token?(session, URI.unescape(request.headers['X-CSRF-TOKEN'] || "") )
      else
        super || form_authenticity_token == URI.unescape(request.headers['X-CSRF-TOKEN'] || "")
      end
    end
end

Upvotes: 0

Related Questions