I'm really having problems with this, and in this case, I don't want to bypass the verify_authenticity_token filter and not change to protect_from_forgery with: :null_session .
In my request method, I set the header with the csrf token as follows:
var token = document.querySelector("meta[name='csrf-token']").content; xhr.setRequestHeader("X-CSRF-Token", token);
And adding a breakpoint to your controller as follows:
def verify_authenticity_token binding.pry super end
I checked that the header is set:
[1] pry(#<MyController>)> request.headers => #<ActionDispatch::Http::Headers:0x007fb227cbf490 @env= {"CONTENT_LENGTH"=>"202", . . . # omitted headers . . . "HTTP_X_CSRF_TOKEN"=>"the-correct-token-from-meta-tag", . . . }
I also tried passing the token as a parameter with the authenticity_token key (as is done with Rails forms) and setting the X-CSRF-Param tag to match (from meta[name="csrf-param"] ).
But I still get:
Can't verify CSRF token authenticity Completed 422 Unprocessable Entity in 14638ms ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken
Has anyone seen this before? Any thoughts on what might cause this?
Thanks in advance!
EDIT:
Following the discussion in the comments of the marflar response, it looks like the token expired when the request is made (verified compared to form_authenticity_token ). This bothers me because the token set to <%= csrf_meta_tags %> expired when the next request arrives. Any thoughts?
EDIT2: Following marflar's tips below, I added the following after_filter to my application controller:
def set_csrf_headers response.headers['X-CSRF-Param'] = request_forgery_protection_token.to_s response.headers['X-CSRF-Token'] = form_authenticity_token end
And I updated xhr.onload in my request method as follows:
namespace.request = = function (type, url, opts, callback) { // code omitted xhr.onload = function () { setCSRFHeaders(xhr); var res = {data: JSON.parse(xhr.response), status: xhr.status}; return callback.call(xhr, null, res); }; // code omitted } function setCSRFHeaders ( xhr ) { var csrf_param = xhr.getResponseHeader('X-CSRF-Param'); var csrf_token = xhr.getResponseHeader('X-CSRF-Token'); if (csrf_param) { document.querySelector("meta[name='csrf-param']").content = csrf_param; } if (csrf_token) { document.querySelector("meta[name='csrf-token']").content = csrf_token; } }
I confirmed that the response headers and then the meta tags get reset properly, however, by the time the next request arrives, this new token has expired. Thoughts?