I have a single page app that authenticates to another domain using CORS. All the requests are JSON requests.
My app can authenticates OK and can make GET requests OK. Authentication is using token_authenticatable. I.e. all requests append '?auth_token=whatever'
So, my actual problem is that when I try to do a PUT request I get a WARNING: Can't verify CSRF token authenticity message in the rails log as well as a CanCan::AccessDenied (You are not authorized to access this page.) exception.
Simply adding skip_before_filter :verify_authenticity_token
to the rails controller fixes the issue.
Therefore I can only conclude that my ajax requests are sending an invalid or empty csrf_token.
I don't really understand how that can be, since I believe I am correctly sending the X-CSRF-Token header correctly with each ajax request.
Basically, my app authenticates and Devise sends back an auth_token and a csrf_token:
render :status => 200, :json => {
:auth_token => @user.authentication_token,
:csrf_token => form_authenticity_token
}
I then store those tokens in my ajax app, and using ajaxSend
in jQuery, set it up so jQuery passes those tokens with each request:
initialize: ->
@bindTo $(document), 'ajaxSend', @appendTokensToRequest
appendTokensToRequest: (event, jqXHR, options) ->
if not @authToken? then return
if @csrfToken?
jqXHR.setRequestHeader 'X-CSRF-Token', @csrfToken
if options.type is 'POST'
options.data = options.data + (if options.data.match(/\=/) then '&' else '') +
$.param auth_token:@authToken
else
options.url = options.url + (if options.url.match(/\?/) then '&' else '?') +
$.param auth_token:@authToken
I can then see in the chrome network tab, that for each GET request the auth_token
param is being sent, as well as the X-CSRF-Token
header.
On PUT requests however it doesn't seem to be working though.
My theory is that CORS is stuffing things up. If you make a CORS request, your browser actually makes an additional OPTIONS request first just to check that you do have permission to access this resource.
I suspect that it is the OPTIONS request which is not passing the X-CSRF-Token header, thus rails immediately invalidates the csrf_token on the rails end. Then when jQuery makes the actual PUT request the csrf_token it passes is no longer valid.
Could this be the problem?
What can I do to prove that? Chrome doesn't seem to show me the OPTIONS requests in the network tab to help me debug the issue.
It's not a major issue, because I can just turn the CSRF stuff off. But I'd like to know why it's not working.