Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

devise user sign_in gives authentication error for CSRF token authenticity token

Tags:

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"=>"[email protected]", "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" =  
'[email protected]' 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 ?"

like image 227
rtcoms Avatar asked Nov 08 '13 14:11

rtcoms


3 Answers

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.

like image 122
Jason Barnabe Avatar answered Sep 23 '22 02:09

Jason Barnabe


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": "[email protected]", "password": "secret" }}'
like image 20
Roberto Brvé Avatar answered Sep 23 '22 02:09

Roberto Brvé


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

like image 43
rtcoms Avatar answered Sep 23 '22 02:09

rtcoms