getting csrf tokens for json post requests to a rails app
Asked Answered
C

2

10

I have been playing around with using rest-client to access a rails app I have written. I've written a quick script to log in and make a post request. Everything is working but I did have to work round the fact that no authenticity_token is served if you make a request for a form in json. I had to make a regular html request in other get the authenticity_token and then included this in the json I submitted as part of my post request. Basically I have a quick an dirty script like the one below

private_resource = RestClient::Resource.new( 'https://mysite.com')

params =  {:user => {:email => '[email protected]', :password => 'please'}}
#log in
login_response = private_resource['users/sign_in'].post(params, :content_type => :json, :accept => :json)
#get cookie
cookie = login_response.cookies
#get json  
json_response = private_resource['products/new'].get(:content_type => :json, :accept => :json, :cookies => cookie)
#another request that returns html form with authenticity token 
response_with_token = private_resource['products/new'].get( :cookies => cookie)
#extract token 
token = Nokogiri::XML(response_with_token).css('input[name=authenticity_token]').first.attr('value')
#update cookie
cookie = response_with_token.cookies
#populate form and insert token
form = JSON.parse(json_response)
form['name'] = "my product"
form['authenticity_token'] = token
#submit the request
private_resource['products'].post(form.to_json, {:cookies => cookie, :content_type => :json, :accept => :json})

There is the option to turn off CSRF protection for json requests but I would rather not do that. I could go the mechanize route or something similar and then I wouldn't worry about json requests with CSRF but I just wanted to play around with doing this stuff with rest-client

I guess I'm just curious to know if there is a reason why no authenticity_token is served for json requests and I'm also wondering if there is a better way of solving the token problem than the pretty hacky approach I've taken here

Cyanocobalamin answered 2/5, 2012 at 12:31 Comment(0)
F
9

Put the below code into your application controller :

def verified_request?
    if request.content_type == "application/json"
      true
    else
      super()
    end
end

And call this method using before_filter .

For more details check : http://blog.technopathllc.com/2011/09/rails-31-csrf-token-authenticity-for.html

And check this issue in rails : https://github.com/rails/rails/issues/3041

Frodeen answered 2/5, 2012 at 13:1 Comment(3)
Thanks for your reply swati, it looks useful. I guess though I was trying to avoid just turning off the CSRF checks. It just seems a little strange to me that rails serves json forms that don't contain any token but then checks for a token. Would it make sense just to serve the json forms with a token included rather than switching off the checks for json content?Cyanocobalamin
welcome ... yes that's only way to by-pass the CSRF token issue . If you want to pass token with your JSON request, you can use header like : headers: { 'X-CSRF-Token': '<%= form_authenticity_token.to_s %>' }Frodeen
check : #7203804 #8503947Frodeen
G
2

In your app/views/products/new.json.jbuilder, add this:

json.authenticity_token form_authenticity_token

This will insert a key "authenticity_token" with value being the token, so in your json_response you get the token as well. Idea from this answer.

Glowworm answered 28/8, 2016 at 1:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.