devise: getting "Can't verify CSRF token authenticity" even if csrf toke in present

I’m doing simple authentication (without ajax or api) and getting error for csrf authenticity token. I’m using latest version of rails and devise

check the post request below

 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)

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Comments: 83 (10 by maintainers)

Commits related to this issue

Most upvoted comments

In my case, all working fine (nginx + puma + rails 5 with turbolinks 5), even without previous advice. But after ssl certificate installation, I have got the same error: Can’t verify CSRF token authenticity.

I added the next line to the nginx config, as solution: proxy_set_header X-Forwarded-Ssl on;

And have no errors now. I used devise, but the problem is not in devise. The usual forms was also broken.

We had the same issue. In session_store.rb we had these settings:

Rails.application.config.session_store :cookie_store, key: "_eqipia_session", domain: :all

We need it because we use subdomains on our staging and production environments and some of services like Xing do not allows us to setup oAuth callback for many subdomains (no * allowed).

Our client reported that he can’t log in into admin panel. Client has access to both environments. The logs errors:

Started POST "/admin/sign_in" for 89.68.139.73 at 2014-07-21 10:37:31 +0000
Completed 422 Unprocessable Entity in 5ms
Processing by Auth::SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"NK1JAQUUAhm7Pi2aMdfepcOs6q90bi1Uqelq/Py6vi8=", "user"=>{"email"=>"admin@eqipia.com", "password"=>"[FILTERED]", "remember_me"=>"0"}}
Can't verify CSRF token authenticity
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
vendor/bundle/ruby/2.1.0/gems/actionpack-4.1.1/lib/action_controller/metal/request_forgery_protection.rb:176:in `handle_unverified_request'
vendor/bundle/ruby/2.1.0/gems/actionpack-4.1.1/lib/action_controller/metal/request_forgery_protection.rb:202:in `handle_unverified_request'
vendor/bundle/ruby/2.1.0/gems/devise-3.2.4/lib/devise/controllers/helpers.rb:182:in `handle_unverified_request'

After some research we figured out that the problem was only present in Chrome. Looking into Resources in Chrome console, I noticed we have the same cookies (one from stage environment and other for production), but of course with different values. It happens because I first logged in to production and then opened new tab and try to log in to staging. With these two cookies, the errors occurs.

eqipia_admin_panel

So in session_store.rb we change name for cookie into dynamic name:

Rails.application.config.session_store :cookie_store, key: "_eqipia_session_#{Rails.env}", domain: :all

This works, the cookies are not mixed up any more.

Disabling verify_authenticity_token is a dangerous fix - it is putting out a fire by vacuuming up smoke. Please don’t disable CSRF protection for your app.

If you have CSRF enabled and you see an authenticity token in the request, check that you actually have a session token in your cookies. Devise has exhaustive tests of this functionality - it is unlikely to be a devise issue.

For those having issues on Rails 5, see https://github.com/plataformatec/devise/pull/4033/files

I have this problem (with Rails 5 and nginx) but proxy_set_header X-Forwarded-Ssl on; is a partial solution at least when i am using facebook OAuth login with Omniauth (and devise) with error like:

Can't verify CSRF token authenticity.

The solution is to use proxy_set_header X-Forwarded-Proto $scheme; instead of proxy_set_header X-Forwarded-Ssl on;

I was experiencing this problem too. It turned out that the prepend: true option for protect_from_forgery was being overwritten. I was using a gem that also declared protect_from_forgery but without the prepend option so it defaulted to false. (In my case auto_session_timeout gem was the culprit.) To fix this I moved my protect_from_forgery after the auto_session_timeout in the ApplicationController.

  class ApplicationController < ActionController::Base
  ...
  
  auto_session_timeout Rails.configuration.session_timeout_length
  
  #has to be after auto_session_timeout so that prepend will not be overwritten.
  protect_from_forgery with: :exception, prepend: true

I was able to solve this problem after quite a lot of troubleshooting. I am using cloudflare with heroku. The fix was to switch Cloudflare’s SSL from Flexible to Full. Then everything worked. That simple. Note that I am using the ‘beta’-ish feature of Heroku’s paid dynos which allow you to upload an SSL certificate for free rather than the SSL Endpoint plugin (if this matters).

My issue with CSRF token related to paper_trail gem. There is a before_action :set_paper_trail_whodunnit I moved it below protect_from_forgery and configure_permitted_parameters then it started working. Hope it helps someone

I have exactly the same of the first post problem, after switching to rails 5. It solves cases removing rails-api but It has included native for Rails 5 and how to solve? =(

Rails 5.0.0.beta3 Devise 4.0.0.rc2 (support for Rails 5)

My error:

Started POST "/admin/sign_in" for 127.0.0.1 at 2016-03-22 12:08:56 -0300
Processing by Devise::SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"c2r8dL0baHl3NLUpW9s3fMoTcxuDaezGwSD2+2B4l7MHJJ0Hnwl4KTuowz1ewwSk6Hklqb/N+W40YJAa6YEBzw==", "user"=>{"email"=>"zullcore@gmail.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "commit"=>"Entrar"}
  User Load (0.4ms)  SELECT  `users`.* FROM `users` WHERE `users`.`email` = 'zullcore@gmail.com' ORDER BY `users`.`id` ASC LIMIT 1
   (0.2ms)  BEGIN
  SQL (0.3ms)  UPDATE `users` SET `current_sign_in_at` = '2016-03-22 15:08:56', `sign_in_count` = 47, `updated_at` = '2016-03-22 15:08:56' WHERE `users`.`id` = 2
  SQL (0.4ms)  INSERT INTO `versions` (`item_type`, `item_id`, `event`, `object`, `created_at`, `object_changes`) VALUES ('User', 2, 'update', '---\nid: 2\nname: Adriano\nprofile: \nadmin: true\ncreated_at: 2016-03-21 23:51:39.000000000 Z\nupdated_at: 2016-03-22 15:08:49.000000000 Z\nemail: zullcore@gmail.com\nencrypted_password: \"$ ... \"\nreset_password_token: \nreset_password_sent_at: \nremember_created_at: \nsign_in_count: 46\ncurrent_sign_in_at: 2016-03-22 15:08:49.000000000 Z\nlast_sign_in_at: 2016-03-22 15:08:49.000000000 Z\ncurrent_sign_in_ip: 127.0.0.1\nlast_sign_in_ip: 127.0.0.1\nphoto_file_name: \nphoto_content_type: \nphoto_file_size: \nphoto_updated_at: \ncreated_by: \nupdated_by: \n', '2016-03-22 15:08:56', '---\ncurrent_sign_in_at:\n- 2016-03-22 15:08:49.000000000 Z\n- 2016-03-22 15:08:56.000000000 Z\nsign_in_count:\n- 46\n- 47\nupdated_at:\n- 2016-03-22 15:08:49.000000000 Z\n- 2016-03-22 15:08:56.000000000 Z\n')
   (47.5ms)  COMMIT

Can't verify CSRF token authenticity

Redirected to http://localhost:3000/admin
Completed 302 Found in 186ms (ActiveRecord: 50.2ms)

Started GET "/admin" for 127.0.0.1 at 2016-03-22 12:08:56 -0300
Processing by Admin::PagesController#dashboard as HTML
Redirected to http://localhost:3000/admin/login
Filter chain halted as :require_login rendered or redirected
Completed 302 Found in 2ms (ActiveRecord: 0.0ms)

I recently caught the same problem.

This commit caused it: image

Looks fine, but turns out it is a bad idea to access current_user in before_action in ApplicationController

Devise controllers are still controllers, and are inherited from ApplicationController.

So I tried to access current user in before_action, before devise finished its protect_from_forgery stuff.

The fix was to put protect_from_forgery before my action

This solved my problem

I overrode the devise sessions controller by creating a new file in controller/users/ with the name of sessions_controller.rb class Users::SessionsController < Devise::SessionsController skip_before_filter :verify_authenticity_token, :only => [:destroy] end

I had this problem, for me it was nothing to do with Devise. It was Rails5 + Heroku + CloudFlare as explained here: http://til.obiefernandez.com/posts/875a2a69af-cloudflare-flexible-ssl-mode-breaks-rails-5-csrf.

“Turn Cloudflare SSL to Full mode. Problem solved.”

Having a similar problem on all browsers with my app: https://github.com/antonkoh/railsrep/tree/master/lesson17/my_app

First way to reproduce:

  1. As unauthorized user open any post on the main page.
  2. In another tab sign in (test00@test.com / 12345678)
  3. On the first tab, enter any symbols in the New Comment field and try to submit.

Second way to reproduce:

  1. As an authorized user (test00@test.com / 12345678) open any post on the main page.
  2. In another tab sign out.
  3. On the first tab try to add a comment.

Both ways end in ActionController::InvalidAuthenticityToken exception. This is also reproduced for any other POST requests from an unrefreshed page.

Devise 3.5.2, Rails 4.2.4

@holoiii Yes, though I didn’t spend a ton of time testing different scenarios. What I ended up doing was this:

  1. Add the Expedited SSL Add On from Heroku
  2. Change Cloudflare SSL from Flexible to Full
  3. Force SSL in ApplicationController ( force_ssl if: :ssl_configured? )

Heroku cannot use apex domains so Expedited SSL will make you use https://www.mydomain.com, however, running with Cloudflare, it works fine using https://mydomain.com

Seems to work.

+1 for

proxy_set_header X-Forwarded-Ssl on;

on rails 5 with nginx and ssl. Note that it worked for some people, whiel other would get authenticity_token error. And i was getting strange redirection behaviour too1

I don’t use devise btw…

@adrianoresende I’m also hitting this issue with Rails5. Did you find a solution?

If the session is empty, obviously the token will not be verified - this is how CSRF protection in Rails works! Check if you’re using httponly or secure flags for your sessions and that they match your desired configuration. If you watch your cookies when you visit the site and you don’t see your app’s session key (config/initializers/session_store.rb key config), then you don’t have a token that can validate against the CSRF token server-side - this will cause the issue.

If you’re not validating CSRF protection for login/logout, a malicious attacker could cause you to logout or login as someone else without your knowledge.

For me the problem was solved when wrote this in my application_controller.rb

class ApplicationController < ActionController::Base protect_from_forgery with: :exception check_authorization :unless => :devise_controller?

Another order of strings above was the reason of exception. Hope it’ll help somebody.

Faced this issue recently. The error was appearing from the fact that one of our new layout files was a missing its csrf_meta_tags. So, for anyone else facing this issue, you might want to check there too! 😄

Rails 5.1, aws elastic beanstalk with cloudfront.

Had the same error and tried everything here to no avail. Fixed it by changing cloudfront behavior settings. Set “Forward Cookies” to “all” from the default “none (Improves Caching)” in Distribution Settings > Behavior > (select behavior) > Edit.

Yep, proxy_set_header X-Forwarded-Proto $scheme; worked for me as well. I was just about to throw a TV out a 2nd story window, and now I can watch it instead…thanks! location @unicorn { proxy_pass http://unicorn; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; }

Rails 4 on chrome.

Findings:

  1. Issue only occurs if user logs in, logs out, and then tries to log in again.
  2. Clearing the cache (shift + cmd + r) fixes the issues temporarily.

Is it possible that Angular continues providing the old CSRF token instead of a new one and this causes the issue?

I’m having this exact same problem in my app, but only in production, not in development/test env. I narrowed it down to this line:

# config/initializers/session_store.rb
Store::Application.config.session_store :cookie_store, key: '_some_key', domain: :all, tld_length: 2

With this line, sessions aren’t destroyed anymore either.


@rtcoms I wasn’t able to reproduce this problem in your sample app, neither in development nor in production (RAILS_ENV=production bundle exec rails server). Could you list exactly what you’re doing to make it fail?

P.S.: Maybe this is being solved by #5567

I tryed the recent rails 7.0.4.3 branch from @carlosantoniodasilva (https://github.com/heartcombo/devise/pull/5567) and the issue related to the “Can’t verify CSRF token authenticity” while using default_url_options seems not be solved.

In my case I get the “Can’t verify CSRF token authenticity” log message after Devise form submission when I use this code (also mentioned here) in app/controllers/application_controller.rb.

class ApplicationController < ActionController::Base
  def default_url_options
    { locale: I18n.locale }
  end
end

I have to submit Devise forms two times to get e.g. the user signed in or get error messages on front end. It also seems this happens randomly!

If I remove the above-mentioned code, Devise seems to work as expected.

Using Rails 7.0.4.2 and Devise 4.9.0

P.S.: Maybe this is being solved by https://github.com/heartcombo/devise/pull/5567

The simplest solution for the problem is do standard things in your controller or you can directly put it into ApplicationController

class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true end

@pdbradley thanks bro, your suggestion works perfect!

Another potential cause worth mentioning: sessions not saving. I had a problem in which my form was generating a csrf token, and it was being sent and received by the server correctly, but it was never matching the token in the session because a new one was being regenerated every request due to a session issue.

I was seeing this issue just now and it was related to me using Heroku + Cloudflare. I had the option set for “Enforce HTTPS for this URL” on Cloudflare. I’ve turned it off and it now works, but now I have to figure out what I’m going to do about SSL.

I’m also seeing it in Rails 5, for what it’s worth.

If you are using forms and turbo-links, the issue can be solved by adding a :authenticity_token => true, like:

<%= form_for @your_model, :remote => true, :authenticity_token => true do |f| %>
<% end %>

I know this can be frustrating but it isn’t helpful to bump this thread saying that you’re experiencing this bug without a reproducible test case. If you have a sample application that exhibits the behavior, we can look at it and try to fix it. A good bug report will include 1. what went wrong 2. what you tried to fix it and 3. a way to reproduce the error.

This isn’t Devise related, as I’m running into the same problem after upgrading to Rails 4 without using the Devise gem at all. Commenting out the ‘:domain => :all, :tld_length => 2’ section ‘fixes’ it, but we need that. Will try and figure out what the actual issue is and create an issue against Rails for it.