2

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

3 Answers 3

10

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.

Sign up to request clarification or add additional context in comments.

2 Comments

This is the correct answer. The reason why this is needed is because the CSRF token is also stored in the Rails session (which by default uses cookies). For the request to be valid, the CSRF token passed in the header must match the value in the session.
I couldn't make this to work because fetch() lowercases all the header keys. And rails server cannot tell that "x-csrf-token" contains the info for "X-CSRF-Token".
0

$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'
})

2 Comments

@lokhi I do not know how fetch works in your case, but $ajax authenticity token actually header being included with beforeSendmethod. BeforeSend: This event, which is triggered before an Ajax request is started, allows you to modify the XMLHttpRequest object (setting additional headers, if need be.)
Downvoted as switching to a different library isn't really a good solution. The answer by Omar Rayward is the correct answer for this question.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.