6

Trying to sign in a user with Devise, I get an invalid authenticity token error.

I have csrf_meta_tags in my layout, and there is an authenticity_token present in the request params. As is suggested in answers to other questions, protect_from_forgery with: :exception is before before_action :authenticate_user!.

If I comment out protect_from_forgery, I see the following in my server log:

Started POST "/users/sign_in" for 127.0.0.1 at 2018-01-19 16:13:46 -0500
Processing by Devise::SessionsController#create as HTML
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"[TOKEN]", "user"=>{"badge_number"=>"0285", "password"=>"[FILTERED]"}, "commit"=>"Log in"}
    User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`badge_number` = '0285' ORDER BY `users`.`id` ASC LIMIT 1
     (0.2ms)  SELECT `divisions`.`id` FROM `divisions` INNER JOIN `divisions_users` ON `divisions`.`id` = `divisions_users`.`division_id` WHERE `divisions_users`.`user_id` = 2
    CACHE  (0.0ms)  SELECT `divisions`.`id` FROM `divisions` INNER JOIN `divisions_users` ON `divisions`.`id` = `divisions_users`.`division_id` WHERE `divisions_users`.`user_id` = 2  [["user_id", 2]]
Redirected to http://localhost:3000/
Completed 302 Found in 141ms (ActiveRecord: 2.1ms)


Started GET "/" for 127.0.0.1 at 2018-01-19 16:13:46 -0500
Processing by IncidentsController#index as HTML
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms)

So it looks like the login is working, but then the redirect to the requested path (/) results in a 401 and being redirected to the login page, as if the login isn't working.

However none of this really explains why I'm getting the authenticity token error in the first place.

Not sure what the next step to investigate the problem might be, given that as far as I can see all the required elements for CSRF token verification are in place.

dfaulken
  • 476
  • 8
  • 18
  • Do you have your configurations set up correctly? This post seems relevant https://stackoverflow.com/questions/28060089/rails-protect-from-forgery-raises-with-exception – gwalshington Jan 19 '18 at 21:45
  • That option wasn't in my configuration before, but adding it and restarting the server yields no change. – dfaulken Jan 19 '18 at 21:53

2 Answers2

4

I fixed this by clearing my cookie for localhost.

I had used SSH tunneling via a localhost port to access the production site, so a cookie based on a conflicting session and secret_key_base was in the localhost domain.

I prevented this from occurring again by prepending the Rails environment to the name of the cookie:

Rails.application.config.session_store :cookie_store, key: "_incidents_#{Rails.env}_session"

So that despite using localhost to access my development and production environments, they would be writing to different cookies by virtue of being in different environments.

dfaulken
  • 476
  • 8
  • 18
1

For Rails 5, note that protect_from_forgery is no longer prepended to the before_action chain, so if you have set authenticate_user before protect_from_forgery, your request will result in "Can't verify CSRF token authenticity." [link]

To resolve this, either change the order in which you call them, or use :

protect_from_forgery with: :exception, prepend: true

fongfan999
  • 2,565
  • 1
  • 12
  • 21
  • Right, I mentioned that in my post. Just to confirm, it should be sufficient to have `protect_from_forgery` directly before `before_action :authenticate_user`, correct? It is the first line in my application controller. Or do I need to add the `prepend: true` in addition to it being first? – dfaulken Jan 21 '18 at 02:13
  • Yes, that's enough, try to restart the server if you still get the error. There is also a nice [post](http://blog.bigbinary.com/2016/04/06/rails-5-default-protect-from-forgery-prepend-false.html) about this – fongfan999 Jan 21 '18 at 03:18
  • Thanks for the post, I understand now. Unfortunately since the calls were already in the correct order, this doesn't seem to be the root of the issue. – dfaulken Jan 21 '18 at 23:00