169

Below is an error, caused by a form in my Rails application:

Processing UsersController#update (for **ip** at 2010-07-29 10:52:27) [PUT]
  Parameters: {"commit"=>"Update", "action"=>"update", "_method"=>"put", "authenticity_token"=>"ysiDvO5s7qhJQrnlSR2+f8jF1gxdB7T9I2ydxpRlSSk=", **more parameters**}

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

This happens for every non-get request and, as you see, authenticity_token is there.

Flip
  • 4,701
  • 5
  • 32
  • 63
Nikita Rybak
  • 64,889
  • 22
  • 150
  • 172

26 Answers26

222

I had the same issue but with pages which were page cached. Pages got buffered with a stale authenticity token and all actions using the methods post/put/delete where recognized as forgery attempts. Error (422 Unprocessable Entity) was returned to the user.

The solution for Rails 3:
Add:

 skip_before_filter :verify_authenticity_token  

or as "sagivo" pointed out in Rails 4 add:

 skip_before_action :verify_authenticity_token

On pages which do caching.

As @toobulkeh commented this is not a vulnerability on :index, :show actions, but beware using this on :put, :post actions.

For example:

 caches_page :index, :show  
 skip_before_filter :verify_authenticity_token, :only => [:index, :show]

Reference: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html

Note added by barlop- Rails 4.2 deprecated skip_before_filter in favour of skip_before_action https://guides.rubyonrails.org/4_2_release_notes.html "The *_filter family of methods have been removed from the documentation. Their usage is discouraged in favor of the *_action family of methods"

For Rails 6 (as "collimarco" pointed out) you can use skip_forgery_protection and that it is safe to use it for a REST API that doesn't use session data.

Szymon Jeż
  • 7,659
  • 4
  • 38
  • 58
  • 3
    That's not likely the case, I didn't know of _caches_page_ before your post. But I'll check _caches_page_ out, thanks. – Nikita Rybak Aug 30 '10 at 18:01
  • 7
    in rails 4 `skip_before_action :verify_authenticity_token` – Sagiv Ofek Feb 27 '14 at 17:48
  • 101
    Isn't this a vulnerability? – quantumpotato Nov 24 '14 at 04:40
  • 6
    this is not a vulnerability on `:index, :show` actions. But be wary of putting this on `:put, :post` actions! – toobulkeh Apr 24 '15 at 22:53
  • 18
    although I agree you have sometimes case where this is needed (like maybe once in lifetime) but you need to realize you are fixing security by disabling security. Not recommended – equivalent8 Oct 12 '17 at 10:37
  • hmm I think someone hit -1 on my comment. I would like to hear why, also read my note on "CSRF protection on single page app API " before answering http://www.eq8.eu/blogs/44-csrf-protection-on-single-page-app-api – equivalent8 Oct 16 '17 at 09:57
  • it's not just rails 4, it's rails 5 too `skip_before_action :verify_authenticity_token works` fine . Look https://stackoverflow.com/questions/1177863/how-do-i-ignore-the-authenticity-token-for-specific-actions-in-rails/34431717 . your skipbeforefilter is for rails 3 – barlop Jul 08 '19 at 16:08
  • 1
    it's not just rails 4, it works for rails 5 too `skip_before_action :verify_authenticity_token` works fine . Look https://stackoverflow.com/questions/1177863/how-do-i-ignore-the-authenticity-token-for-specific-actions-in-rails/34431717 your skipbeforefilter is for rails 3. Looks like rails 5.2 one should use `skip_forgery_protection` – barlop Jul 08 '19 at 16:16
  • 2
    In Rails 6 you can use `skip_forgery_protection` and I confirm that it is safe to use it for a REST API that doesn't use session data – collimarco Nov 04 '19 at 16:58
82

For me the cause of this issue under Rails 4 was a missing,

<%= csrf_meta_tags %>

Line in my main application layout. I had accidently deleted it when I rewrote my layout.

If this isn't in the main layout you will need it in any page that you want a CSRF token on.

James McMahon
  • 45,276
  • 62
  • 194
  • 274
  • 2
    We are also receiving this error. But it's intermitted. Could this be the reason or would not having this affect every request with an error? – Ryan-Neal Mes Oct 01 '15 at 14:21
  • @Ryan-NealMes, if your template is missing that line you will get the error. So it's possible some of your templates have it and the others do not. – James McMahon Oct 01 '15 at 21:02
  • 1
    @JamesMcMahon thanks, I figured out my case is actually caused by users clearing their cookies or having cookies blocked. Learnt loads from this question! – Ryan-Neal Mes Oct 02 '15 at 07:21
68

There are several causes for this error, (relating to Rails 4).

1. Check <%= csrf_meta_tags %> present in page layout

2. check authenticity token is being sent with AJAX calls if using form_for helper with remote: true option.If not you can include the line <%= hidden_field_tag :authenticity_token, form_authenticity_token %> withing the form block.

3. If request is being sent from cached page, use fragment caching to exclude part of page that sends request e.g. button_to etc. otherwise token will be stale/invalid.

I would be reluctant to nullify csrf protection...

GoodViber
  • 721
  • 5
  • 2
42

Just adding the authenticity_token in form fixed it for me.

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
Deepak Mahakale
  • 19,422
  • 8
  • 58
  • 75
38

ActionController::InvalidAuthenticityToken can also be caused by a misconfigured reverse proxy. This is the case if in the stack trace, you get a line looking like Request origin does not match request base_url.

When using a reverse proxy (such as nginx) as receiver for HTTPS request and transmitting the request unencrypted to the backend (such as the Rails app), the backend (more specifically: Rack) expects some headers with more information about the original client request in order to be able to apply various processing tasks and security measures.

More details are available here: https://github.com/rails/rails/issues/22965.

TL;DR: the solution is to add some headers:

upstream myapp {
  server              unix:///path/to/puma.sock;
}

location / {
  proxy_pass        http://myapp;
  proxy_set_header  Host $host;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto $scheme;
  proxy_set_header  X-Forwarded-Ssl on; # Optional
  proxy_set_header  X-Forwarded-Port $server_port;
  proxy_set_header  X-Forwarded-Host $host;
}
vmarquet
  • 1,747
  • 2
  • 19
  • 33
  • Wow, I've been searching 3 hours for a solution for this, and this was it, thanks! – evexoio Sep 19 '18 at 07:05
  • thank you very much 6 hours of trying to solve this on rails side – Joe Half Face Dec 23 '18 at 22:09
  • In my case, I had a proxy_set_header Origin http://$http_host and when I switched to HTTPS I couldn't log into my site anymore. The solution was to use proxy_set_header Origin $scheme://$http_host - this answer helped by reminding me to look for the actual error message in the log. – EK0 Mar 03 '21 at 17:03
  • This happened to me after I upgraded an app from Rails 5.1 to 5.2. – Paul A Jungwirth Apr 08 '21 at 00:38
32

The authenticity token is a random value generated in your view to prove a request is submitted from a form on your site, not somewhere else. This protects against CSRF attacks:

http://en.wikipedia.org/wiki/Cross-site_request_forgery

Check to see who that client/IP is, it looks like they are using your site without loading your views.

If you need to debug further, this question is a good place to start: Understanding the Rails Authenticity Token

Edited to explain: It means they are calling the action to process your form submit without ever rendering your form on your website. This could be malicious (say posting spam comments) or it could indicate a customer trying to use your web service API directly. You're the only one who can answer that by the nature of your product and analyzing your requests.

Community
  • 1
  • 1
Winfield
  • 18,155
  • 3
  • 49
  • 65
  • 1
    Thanks, but I already know what authenticity token is. _Check to see who that client/IP is, it looks like they are using your site without loading your views._ Sorry, what "without loading views" means? – Nikita Rybak Jul 29 '10 at 16:20
  • 1
    I means that somebody (probably a spammer) could be submitting data to your form without going through your application's user interface. It's possible to do this using a command line program such as curl, for example. – John Topley Jul 29 '10 at 16:32
  • John has it exactly right. It means they are calling the action to process your form submit without ever rendering your form on your website. This could be malicious (say posting spam comments) or it could indicate a customer trying to use your web service API directly. You're the only one who can answer that by the nature of your product and analyzing your requests. – Winfield Jul 29 '10 at 16:35
  • Ok, I misunderstood Winfield's comment. I thought the app wasn't somehow configured to 'load my views' when I use browser. – Nikita Rybak Jul 29 '10 at 16:36
  • 1
    I also had another thought, these requests include a token, but it's not valid. This could be caused by caching the page rendering your form or something else that causes a stale version of the form potentially. – Winfield Jul 29 '10 at 16:43
21

too late to answer but I found the solution.

When you define you own html form then you miss authentication token string that should be sent to controller for security reasons. But when you use rails form helper to generate a form you get something like following

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;">
    <input name="authenticity_token" type="hidden" 
      value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
    .
    .
    .
  </div>
</form>

So the solution to the problem is either to add authenticity_token field or use rails form helpers rather then removing , downgrading or upgrading rails.

pegasuspect
  • 965
  • 4
  • 14
amjad
  • 2,586
  • 6
  • 22
  • 40
10

If you have done a rake rails:update or otherwise recently changed your config/initializers/session_store.rb, this may be a symptom of old cookies in the browser. Hopefully this is done in dev/test (it was for me), and you can just clear all browser cookies related to the domain in question.

If this is in production, and you changed key, consider changing it back to use the old cookies (<- just speculation).

kross
  • 3,575
  • 2
  • 27
  • 54
7

I had this issue with javascript calls. I fixed that with just requiring jquery_ujs into application.js file.

Michael Koper
  • 8,866
  • 6
  • 40
  • 56
  • Yes correct, I also had this issue and I added jquery_ujs in application js. It worked. – Abhi Aug 03 '17 at 05:38
4

We had the same problem, but noticed that it was only for requests using http:// and not with https://. The cause was secure: true for session_store:

Rails.application.config.session_store(
  :cookie_store,
  key: '_foo_session',
  domain: '.example.com',
  secure: true
)

Fixed by using HTTPS ~everywhere :)

Darep
  • 113
  • 1
  • 7
  • I encountered this when using `rails s` (non-SSL) instead of the SSL endpoint I have set up for development. It wasn't until I read your comment that I realized what I was doing. Once I switched back to using SSL, things started working again. Thanks! – Karl Wilbur Jun 17 '18 at 18:03
  • 1
    I faced this issue in development. Instead of `secure: true` I wrote `secure: !Rails.env.development?` – murb Jun 16 '19 at 20:51
2

Add

//= require rails-ujs 

in

\app\assets\javascripts\application.js
Carlos Castillo
  • 2,963
  • 2
  • 12
  • 10
1

For rails 5, it better to add protect_from_forgery prepend: true than to skip the verify_authentication_token

aadeshere1
  • 65
  • 1
  • 9
0

I had this problem and the reason was because I copied and pasted a controller into my app. I needed to change ApplicationController to ApplicationController::Base

user2954587
  • 4,079
  • 4
  • 32
  • 78
0

I had the same issue on localhost. I have changed the domain for the app, but in URLs and hosts file there was still the old domain. Updated my browser bookmarks and hosts file to use new domain and now everything works fine.

MoD
  • 244
  • 2
  • 9
0

Maybe you have your NGINX setup for HTTPS but your certificates are invalid? I've had a similar problem in the past and redirecting from http to https solved the problem

montrealmike
  • 10,771
  • 6
  • 56
  • 80
0

I have checked the <%= csrf_meta_tags %> are present and clearing cookies in browser worked for me.

Praveen KJ
  • 510
  • 2
  • 7
  • 19
0

Following Chrome Lighthouse recommendations for a faster application load, I have asynced my Javascript:

views/layout/application.html.erb

<%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload', async: true %>

This broke everything and got that Token error for my remote forms. Removing async: true fixed the problem.

Maxence
  • 1,245
  • 2
  • 13
  • 25
0

This answer is much more specific to Ruby on Rails, but hopefully it will help someone.

You need to include the CSRF token with every non-GET request. If you're used to using JQuery, Rails has a helper library called jquery-ujs that builds on top of it and adds some hidden functionality. One of the things it does is automatically includes the CSRF token in every ajax request. See here.

If you switch away from it like I did you might find yourself with an error. You can just submit the token manually or use another library to help scrape the token from the DOM. See this post for more detail.

user2490003
  • 7,930
  • 12
  • 59
  • 115
0

For Development environment, I tried many of these attempts to fix this issue, in Rails 6. None of them helped. So if none of these suggestions worked for you, try below.

The only solution I found was to add a txt file into your /tmp folder.

In your app's root directory, either run:

touch tmp/caching-dev.txt

Or manually create a file by that name in your /tmp folder. Since this fixed it for me, I assume the root of the issue is a caching conflict.

Twistedben
  • 111
  • 8
0

Running rails dev:cache in my console fixed this for me! (Rails 6)

I think it might be something to do with Turbolinks, but CSRF only seems to work when local caching is enabled.

Jon Lemmon
  • 3,299
  • 2
  • 21
  • 37
0

This happened to me when carrying out manual tests of the sign up process of my application (signing up/in with multiple users).

A very simple and pragmatic solution may be to do what I did, and use a different browser (or incognito if using chrome).

This was a much better solution in my case than disabling security features!!

stevec
  • 15,490
  • 6
  • 67
  • 110
0

This happened to me when upgrading from Rails 4.0 to 4.2.

The 4.2 implementation of verified_request? looks at request.headers['X-CSRF-Token'], whereas the header my 4.0 app had been getting was X-XSRF-TOKEN. A quick fix in my ApplicationController was to add the function:

  def verify_authenticity_token
    request.headers['X-CSRF-Token'] ||= request.headers['X-XSRF-TOKEN']
    super
  end
JellicleCat
  • 23,907
  • 21
  • 96
  • 144
0

I experienced a similar error in Rails 6. Having tried the solutions above, I did a form review and saw that I had used a <button>.....</button> HTML tag in my form instead of submitting through Rails

<%= form.submit %>
form helper. Changing to the form helper resolved the issue.
-1

In rails 5, we need to add 2 lines of code

    skip_before_action :verify_authenticity_token
    protect_from_forgery prepend: true, with: :exception
giapnh
  • 1,554
  • 16
  • 17
-2

Installing

gem 'remotipart' 

can help

Aamir
  • 13,234
  • 9
  • 51
  • 63
Alexei.B
  • 190
  • 5
  • 3
    although this might the answer, but its also helpful to include the essential part of the answer and explain why/how it works. – Roy Lee Nov 16 '15 at 02:52
-17

Problem solved by downgrading to 2.3.5 from 2.3.8. (as well as infamous 'You are being redirected.' issue)

Bill the Lizard
  • 369,957
  • 201
  • 546
  • 842
Nikita Rybak
  • 64,889
  • 22
  • 150
  • 172