5

I'm trying to make an authenticated post request, and I need the CSRF. When I log in, it isn't generating the _csrf_token for some reason:

2.0.0p247 :126 >   app.post '/community_members/login', {"refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
 => 302
2.0.0p247 :127 > app.session
 => {"warden.user.refinery_user.key"=>[[56], "$2a$10$gr/rTcQfuXnes1Zml3qOPu"], "session_id"=>"f77d89cef9ff1710890f575b479bb690"}

I tried app.session[:_csrf_token] ||= SecureRandom.base64(32) before login, but it is always deleted. I also tried to get the login form first, but _csrf_token is still not set.

2.0.0p247 :133 >   app.get '/community_members/sign_in'
2.0.0p247 :134 > app.response # authenticity_token is burried in the raw HTML
2.0.0p247 :136 >   app.post '/community_members/login', {"refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
2.0.0p247 :137 > app.session
 => {"warden.user.refinery_user.key"=>[[56], "$2a$10$gr/rTcQfuXnes1Zml3qOPu"], "session_id"=>"c2c564229e55b81ca788788558d7d11a"}

How do I manually generate the token to pass to the post request?


Oh ok, I think I need to submit the authenticity_token (that is set in the session after GETing the login form) to the login form, then it puts it in the session permanently! This worked:

app.post '/community_members/login', {'authenticity_token'=>'GfT5GtcUmYQ927oNQmh2MR0NKQucGSx8mtMg3Ph9kXw=', "refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}

Here is a full example: https://stackoverflow.com/a/23899701/148844

3 Answers 3

9

I felt like using Nokogiri to parse the response was a little heavy so I wrote a simple regex to pull the authenticity token out of the response.

app.get  '/api_with_form'
authenticity_token = app.response.body.match(/<[^<]+authenticity_token[^>]+value="([^"]+)"[^>]+>/)[1]

I'm using this to log in

app.get  '/users/sign_in'
authenticity_token = app.response.body.match(/<[^<]+authenticity_token[^>]+value="([^"]+)"[^>]+>/)[1]
app.post '/users/sign_in', 'user[email]' => 'my_username', 'user[password]' => 'my_password', authenticity_token: authenticity_token
Sign up to request clarification or add additional context in comments.

Comments

3

Unless you load the page before you do app.post, there is no CSRF token generated to begin with. Manually generating a new one will not help because it won't match what is stored on the server, which is likely to be some null value.

You need to load the page, parse out the CSRF token, and then use that one.

Alternately, you can load the form, try to read the CSRF token out of app.session[:_csrf_token] and use that.

3 Comments

Even if I get the login form first, then post, session[:_csrf_token] is not set.
I had to submit the authenticity_token as part of the login!
@Chloe, I assume the accept means that you realized you have to load the login page first, and then get the token?
3

I use these commands in rails console:

app_controller = ActionController::Base::ApplicationController.new
app_controller.request = ActionDispatch::Request.new({})
app_controller.send(:form_authenticity_token)

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.