Rails 4 upgrade throwing InvalidAuthenticityToken - ruby-on-rails

My application just upgraded to Rails 4 and we're starting to see random InvalidAuthenticityToken errors. I have done a bunch of investigating but not yet found a solution. Anyone know what happened and how to fix it?
Calling out things that appeared in other similar SO questions but do not apply to me:
We call protect_from_forgery with: :exception in ApplicationController, but we were doing this in Rails 3 as well and did not have this error.
I have confirmed these are normal users using the website in a standard fashion; these are not CSRF attempts.
These are not API calls, they are standard web form submissions.
The authenticity token is present in both the form (via Rails form_for or form_tag generation) and in the submitted request.
My sessions should not have an expiration set, since I do not set an expiration time and the Rails default is forever, and my users don't often log in or out (so expired tokens are unlikely, as is "had a tab open, logged into a separate tab, went back to open tag and attempted action").
The csrf_meta_tag was generating the same tokens as my forms and removing it does not help.
My users confirmed they experienced this on at minimum Firefox, Chrome and Safari.
All code is available on Github.
Possibly relatedly: if I change my development secret_key_base in secrets.yml and change my session_store.rb file to use:
Rails.application.config.session_store :cookie_store, key: '_glowfic_constellation_' + Rails.env, domain: 'glowfic.com', tld_length: 2 and restart the server, I am logged out and can reliably experience this error 100% of the time when attempting to log in.
Edit calling out a couple more things:
I can't force clear all sessions because I use cookie stores, but I've already reset the secret_key_base and cookie name in production, which (hard to tell but I think) helped? But did not fix the issue.
The "possibly related" seems to be unrelated, and to have been related to the domain "glowfic.com" not supporting "localhost"; if I use the domain localhost instead, I can't reproduce locally.

Related

Both rails applications have an CSRF authentication problem in my local dev environment

I have two rails applications. From one day to another both produce an ActionController::InvalidAuthenticityToken exception. I can call the login page, but when I try to login, the exception raises and in the console I find "Can't verify CSRF token authenticity".
What I tried:
different browsers
I checked out older releases from which I definitely know, that it had been working.
I do not post any code because I do not think that it would help. It must have an external reason, because the problem occurred on two separate apps in the same moment.
The reason was, that I forbid Cookies for localhost in Chrome.
What I can't figure out is, why I had the same problem in Opera, though I did not forbid cookies there.

Why would Rails 5.2 cookies not reach the browser on a development environment?

Your help is hugely appreciated and valued. Thank you in advance if you take some of your time to read this issue and eventually respond.
I'm working with a standard authentication system storing a user_id and remember_token in cookies.
When filling-in a login form, a new token gets generated for this user, and stored in cookies as such:
# Remembers a user in a persistent session.
def remember(user)
user.remember # Generates a remember token + digest and saves the digest on the user side
cookies.signed.permanent[:user_id] = user.id
cookies.permanent[:remember_token] = user.remember_token
end
I noticed the issue when after submitting the form with correct login information, the user always got redirected immediately back to the login page.
This is because the user_id and remember_token were nil when reaching the action following sessions#create. They also did not appear in the console of the browser (tried on Safari and Chrome with identical results). I thought the cookies were lost during the redirect.
But playing further, I included attempts to write cookies directly on a regular 'get' action, before any redirect:
class SessionsController < ApplicationController
def new
cookies[:hello] = {value: 'store_me_please', expires: 10.years.from_now}
cookies.permanent[:a_true_cookie] = true
cookies.permanent.signed[:remember_me] = 123
session[:hello] = 'store_me_in_session_please'
if logged_in?
redirect_to user_path(current_user)
else
render layout: "unauthenticated"
end
end
end
And noticed that the cookie store in the browser would remain invariably empty while accessing the action. Nothing would get written.
I thought it could be caused by a csrf protection problem as rails can clear the session if it fails to authenticate its token. So I commented out "protect_from_forgery" in the application_controller, but saw no change.
The secret_key_base seems to be in place in the new credentials.yml file; although it's the first Rails 5.2 App for which I deal with such issues, so I could be missing something in the configuration.
I also added the following configuration line to application.rb, which then triggers a "ActionController::InvalidAuthenticityToken" exception on submitting the form, despite the "#protect_from_forgery with: :exception" line being commented out.
config.session_store :cookie_store
It seems to me that the cookies are never sent out by the Rails App to the browser. What could cause this behavior?
I could not find any clean way around this issue, or find the exact cause. My intuition goes toward the following possible causes (only for documentation purpose, in case someone hits the same issue):
- Cookie signature problem caused by a corrupted secret_key_base
- CSRF/CORS issue also caused by a corrupted secret_key_base or interference with authenticity token, causing rails to dismiss the cookies before sending the response.
- Some config setting not set properly preventing a normal execution.
I spent 3 full time days trying to diagnose what was causing this and still was unlucky.
The only solution I could come up with was to transfer all the files of this non-functional App, to a copy of a functional one, with a practically identical config.
The process took an hour and solved the issue -but alas did not give the cause.

Session cookie not being created only in production

I've been struggling with this for a while now and just can’t figure out why this is not working. I use Firefox/Firebug to see the session cookie being created in Development mode but when I run locally in Production the session cookie is not created. This, of course, causes all sorts of grief when the CSRF token is not in the session cookie and an exception is thrown.
The obvious place to look is in production.rb vs development.rb as all the rest of the code is the same however I can't see anything wrong there and I compared both files to a (test) newly created rails app.
Config Info:
session_store => cookie_store (rails default)
protect_from_forgery with: :exception (application_controller)
Any thoughts are appreciated. Thanks, Art
When I recently encountered the same situation, it turned out to be a problem with misconfigured session cookie domain.
Look into the HTTP headers your application sends with the responses. I guess the Set-Cookie header is sent for the session cookie as expected, but the browser refuses to save the cookie, because domain specified in the header doesn't match the actual production domain your application is running on.
To fix this, fix domain setting in the session store configuration.
Nope, neither of these were the problem. It was using Rack::Cached. I didn't have time to track down the why of it, just that removing it from my build stopped the problem without having to do anything else. Wish I'd had time to track this down further to help you all out.

Rails sessions not saving

I'm in the process of upgrading a Rails app from Rails 2 directly to Rails 4. I'm using the new /config/initializers/session_store.rb file, with CookieStore, but for some reason my sessions are not saving.
When trying to do something along the lines of
render :text => "#{request.session_options[:id]}"
I get a new session ID every refresh.
I've tried on different browsers, and all should be accepting cookies.
I have no idea what's going on. Why won't these sessions persist?!
Edit: thank you all for your suggestions. Here's a little more information, and a few things I've noticed:
First, about my set up -- I'm running the server with Rails 4/Ruby 2 through RVM on an Ubuntu VM on my Windows 7 machine.
Although I'm upgrading from Rails 2, that only really applies to the models/controllers/views/etc -- I generated a new Rails 4 application for all of the supporting infrastructure.
I created another application on the same VM that JUST sets a session and then displays, and that works fine.
What the session is storing varies slightly depending on what the user is doing, but usually it holds simply a user id (just an integer), and occasionally a little more -- (i first noticed this manifesting itself while trying to pass an OAuth token from the OAuth gem.)
I've noticed that if the VM's system clock falls behind the Windows 7 host machine clock, the user id sessions hold. That causes other problems, especially with OAuth, but there seems to just be a time issue somewhere. I've tried doing things like removing the time zone from my environments/development.rb, but that did not help.
As a general answer a couple of possible problems are
Session size over 4K limit (which is apparently the case).
CookieOverflow is raised if you attempt to store more than 4K of data.
Please, bear in mind that if you store an object in session, the object is previously serialized before storing it and its size would be bigger. More info on the general problem and possible solutions for the specific problem, here.
Problems with CSRF protection.
If the security token doesn't match what was expected, the session
will be reset
Edit: To check if it is a CSRF case, you can, as Abdo comments below, temporarily disable the protect_from_forgery line in ApplicationController
I had a similar symptoms. It turns out it was because I added the rails-api gem and it totally broke session saving.
From: Railscasts Episode 415 Upgrading to Rails 4
There’s one more configuration change we need to make, in the secret
token initializer. In Rails 4 the configuration option in this file
has been renamed from secret_token to secret_key_base. We’ll need to
specify both options while we’re transitioning from Rails 3 but once
we’ve successfully migrated our application we can remove the
secret_token option. It’s best to use a different token for our
secret_key_base.
This is necessary because we’re moving from a serialized cookie stored
on the client to an encrypted cookie. This prevents users from easily
being able to see the contents of their session cookies.
The episode includes a very good series of tips regarding upgrading from 2 to 4 and I was able to do that successfully using this tutorial.

Rails - Session not saving

I have a session that is set but it does not appear to carry over to other pages. I'm on Rails 2.3.5 and Ruby 1.8.7. Has anyone else experienced this issue?
I've had this issue in Rails 3.1 when CSRF verification fails. This can happen if you use a tag manually rather than generate it via one of the built-in methods provided by Rails.
Search your log file for "csrf" (case insensitive search). If you see a log entry showing a csrf failure, it's likely Rails is resetting your session.
You may be losing your session between requests which can happen if it's not established properly in the first place. If you examine your cookies you may see the session identifier changing, being re-assigned, because of a validation failure.
It's also possible that it's being assigned to a domain that the browser subsequently rejects. This happens if an application is configured to use a specific domain, and is then re-hosted under a different one, even localhost.
You might have not used csrf meta tag in your layout. Try removing ' protect from forgery ' in application_controller.rb in controllers folder. Then try running the app again, if it works then you didn't add tags to your layout.

Resources