22

I am using devise (latest version - 3.2.0) with rails (latest version - 4.0.1)

I'm doing simple authentication (without ajax or api) and getting an error for CSRF authenticity token. Check the POST request below

started POST "/users/sign_in" for 127.0.0.1 at 2013-11-08 19:48:49 +0530
Processing by Devise::SessionsController#create as HTML

 Parameters: {"utf8"=>"✓",    
 "authenticity_token"=>"SJnGhXXUXjncnPhCdg3muV2GYCA8CX2LVFV78pqddD4=", "user"=> 
{"email"=>"a@a.com", "password"=>"[FILTERED]", "remember_me"=>"0"},
"commit"=>"Sign in"}

Can't verify CSRF token authenticity
 User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."email" =  
'a@a.com' LIMIT 1
(0.1ms)  begin transaction
SQL (0.4ms)  UPDATE "users" SET "last_sign_in_at" = ?, "current_sign_in_at" = ?,
"sign_in_count" = ?, "updated_at" = ? WHERE "users"."id" = 2  [["last_sign_in_at", Fri,
08 Nov 2013 14:13:56 UTC +00:00], ["current_sign_in_at", Fri, 08 Nov 2013 14:18:49 UTC
+00:00], ["sign_in_count", 3], ["updated_at", Fri, 08 Nov 2013 14:18:49 UTC +00:00]]
(143.6ms)  commit transaction
Redirected to http://localhost:3000/
Completed 302 Found in 239ms (ActiveRecord: 144.5ms | Search: 0.0ms)

The root url points to home#new, which is like

class HomeController < ApplicationController
   before_action :authenticate_user!
   def index
   end
end

Sign_in page generated html view is like:

  • meta tags

    <meta content="authenticity_token" name="csrf-param" />
    <meta content="aV+d7Z55XBJF2VtyL8V3zupR3OwhaQ6UHNtlQLBQf5Y=" name="csrf-token" />
    
  • form

    <form accept-charset="UTF-8" action="/users/sign_in" class="new_user" id="new_user" 
    method="post">
    <div style="margin:0;padding:0;display:inline">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden
    value="aV+d7Z55XBJF2VtyL8V3zupR3OwhaQ6UHNtlQLBQf5Y=" />
    </div>
    <div><label for="user_email">Email</label><br />
    <input autofocus="autofocus" id="user_email" name="user[email]" type="email" value="" />
    </div>
    
    <div><label for="user_password">Password</label><br />
    <input id="user_password" name="user[password]" type="password" /></div>
    
    <div><input name="user[remember_me]" type="hidden" value="0" />
    <input id="user_remember_me" name="user[remember_me]" type="checkbox" value="1" /> 
    <label for="user_remember_me">Remember me</label></div>
    
    <div><input name="commit" type="submit" value="Sign in" /></div>
    </form>
    

The authentication request even updates the last_sign_in_at and sign_in_count values, but when I try to access current_user in controller it comes as nil.

According to me it is not actually signing in user. But then question comes "why it is updating last_sign_in_at/sign_in_count value in the user table ?"

das-g
  • 9,718
  • 4
  • 38
  • 80
rtcoms
  • 783
  • 1
  • 8
  • 19
  • 1
    I had months ago a similar issue and I could resolve with: Deleting all cookies and cache in my browser. Hope its for you as well – Flo Nov 08 '13 at 16:19
  • well, that may be the case. let me try. – rtcoms Nov 08 '13 at 16:53
  • It's not working even after clearing cache and cookies. I even trien in different browser. – rtcoms Nov 08 '13 at 19:21
  • 1
    Can you post your view for the registration page? And also is '<%= csrf_meta_tags %>' in your application.html.erb file? – Philip7899 Nov 10 '13 at 23:05
  • I've updated my question with generated views html code. – rtcoms Nov 12 '13 at 10:33
  • Did you see the posts: http://stackoverflow.com/questions/7203304/warning-cant-verify-csrf-token-authenticity-rails , http://stackoverflow.com/questions/11986939/cant-verify-csrf-token-authenticity-in-rails , http://stackoverflow.com/questions/15040964/warning-cant-verify-csrf-token-authenticity-in-case-of-api-development , http://stackoverflow.com/questions/9362910/rails-warning-cant-verify-csrf-token-authenticity-for-json-devise-requests ? – Малъ Скрылевъ Nov 13 '13 at 13:56
  • Yes. Those are for either AJAX request or api call related. Mine is simple html request as I mentioned in the question – rtcoms Nov 13 '13 at 16:58
  • Could you add the versions of devise and rails that you're using for future readers of this question? – carols10cents Nov 14 '13 at 02:11
  • Added version of rails and devise – rtcoms Nov 14 '13 at 04:22
  • Similar authentication issue. I think you can check here: http://stackoverflow.com/a/16264496/1915916 – TheAshwaniK Nov 14 '13 at 15:00
  • The case in link provided is that the request is made via curl request. In my case it's made via form rendered by rails. – rtcoms Nov 14 '13 at 15:46

4 Answers4

14

When the CSRF token is not correct, Rails will not read or do any updates to the session. It will still do any other actions the controller specifies, which explains why you see the DB update but don't end up logged in.

I notice that the authenticity_token in your log and in your page do not match. I realize this just may be because you captured a different request, but you should check that the one on the page matches the one in the log for the same request. I'm also assuming that you are using the proper tag in your view which generates a different authenticity_token each time, and are not just hard-coding the HTML input.

Do you see the same issue with forms unrelated to devise? If not, as a workaround, you can exempt your action from the CSRF check with the following code in your controller:

protect_from_forgery except: :sign_in

The odds of a CSRF attack against your sign in action seems pretty remote (<-pun) to me.

Also, if it's just with devise, then I'd suggest you file an issue with them, which you've already done.

jb_314
  • 1,373
  • 2
  • 17
  • 28
  • log and form authenticity tokens are different because I added code for view/form part later to the question. I just checked it now and both are same, so I think that should not be the case for the above issue – rtcoms Nov 16 '13 at 09:21
5

Add this on the Application Controller (this works on Rails 5)

protect_from_forgery unless: -> { request.format.json? }

Add this to the Devise SessionController

skip_before_action :verify_authenticity_token, only: [:create]

Try it with curl

curl -X POST -v -H 'Content-Type: application/json' http://0.0.0.0:3000/users/sign_in -d '{"user" : {"email": "name@mail.com", "password": "secret" }}'
Roberto Brvé
  • 249
  • 3
  • 6
2

There was no problem with devise gem . I removed 'rails-api' gem and my app started working.

rtcoms
  • 783
  • 1
  • 8
  • 19
1

I fixed the same issue just removing "remote: true" option in view: changed form_for(model, remote: true) to form_for(model)

guest
  • 11
  • 1