How do I generate a CSRF token from the Rails console?
Asked Answered
A

3

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://mcmap.net/q/80005/-how-can-i-call-controller-view-helper-methods-from-the-console-in-ruby-on-rails

Agitate answered 28/5, 2014 at 21:18 Comment(0)
P
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
Peggi answered 29/7, 2014 at 17:42 Comment(0)
P
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.

Prolong answered 28/5, 2014 at 21:22 Comment(3)
Even if I get the login form first, then post, session[:_csrf_token] is not set.Agitate
I had to submit the authenticity_token as part of the login!Agitate
@Chloe, I assume the accept means that you realized you have to load the login page first, and then get the token?Prolong
T
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)
Trainbearer answered 17/6, 2016 at 5:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.