17

After upgrading to Rails 4.1.4 from Rails 3.2, accessing the application with an existing session (from the older Rails 3.2 version) causes an internal server error. backtrace:

JSON::ParserError - 795: unexpected token at {
I"session_id:ETI"%fa78a4ee07ac952c9b034ebc6199f30b;':
  /Users/.../.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/json/common.rb:155:in `parse'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:388:in `load'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:428:in `deserialize'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:183:in `verify_and_upgrade_legacy_signed_message'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:550:in `[]'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:114:in `get_cookie'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:90:in `block in unpacked_cookie_data'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/abstract_store.rb:51:in `stale_session_check!'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:89:in `unpacked_cookie_data'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:83:in `block in extract_session_id'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/abstract_store.rb:51:in `stale_session_check!'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:82:in `extract_session_id'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:49:in `block in []'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:48:in `[]'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:70:in `id'
  rack (1.5.2) lib/rack/session/abstract/id.rb:282:in `current_session_id'
  rack (1.5.2) lib/rack/session/abstract/id.rb:288:in `session_exists?'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:152:in `exists?'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:172:in `load_for_read!'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:89:in `[]'
  warden (1.2.3) lib/warden/session_serializer.rb:30:in `fetch'
  warden (1.2.3) lib/warden/proxy.rb:212:in `user'
  warden (1.2.3) lib/warden/proxy.rb:318:in `_perform_authentication'
  warden (1.2.3) lib/warden/proxy.rb:104:in `authenticate'
  warden (1.2.3) lib/warden/proxy.rb:114:in `authenticate?'
  devise (3.2.4) lib/devise/rails/routes.rb:460:in `block in constraints_for'
  actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:38:in `block in matches?'
  actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:36:in `matches?'
  actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:45:in `call'
  actionpack (4.1.4) lib/action_dispatch/journey/router.rb:71:in `block in call'
  actionpack (4.1.4) lib/action_dispatch/journey/router.rb:59:in `call'
  actionpack (4.1.4) lib/action_dispatch/routing/route_set.rb:678:in `call'
  ...

I tried to change the session cookie key name, but it seems to be stuck on session_id.

# initializers/session_store.rb
MyApp::Application.config.session_store :cookie_store, key: 'myapp_session'

Please help! A great solution would also be to delete all session cookies before they hit the rails middleware, but i have no idea how to do that..

Yossi Shasho
  • 3,632
  • 31
  • 47

3 Answers3

34

Found the answer here: https://github.com/rails/rails/issues/15111

My settings had

# initializers/cookie_serializer.rb
Rails.application.config.action_dispatch.cookies_serializer = :json

I changed it to

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

And that did the trick

Yossi Shasho
  • 3,632
  • 31
  • 47
  • 2
    I suspect the same error will happen if later, you switch to :json and someone who didn't visit your app since long ago comes back. Wondering how to handle that scenario! Maybe changing the secret will be enough, not sure. – Thibaut Barrère Oct 03 '14 at 10:06
  • I think the point of the `hybrid` serializer is to solve the scenario you described. – Yossi Shasho Oct 05 '14 at 07:50
  • 2
    To clarify: I'm concerned (but will verify) that keeping the hybrid activated on the long run will leave security issues, since yaml can be passed etc. If this is true, switching to :json instead of :hybrid at some point would be a good idea otherwise it defeats the purpose completely. My concern is how to avoid errors 500 when switching to :json for good, and someone with an old cookie comes in. I will play around and investigate to understand that part. – Thibaut Barrère Oct 05 '14 at 09:20
  • 2
    @ThibautBarrère I just encountered this problem when setting my cookies_serializer to :json. I changed my secret and it worked fine, with no 500 error, despite the fact that my browser had an old session cookie. – ctc May 08 '15 at 19:33
  • 2
    There is no need to use hybrid, if you're OK with changing your secret. – ctc May 08 '15 at 19:33
  • It's help me! The error was: `JSON::ParserError (795: unexpected token at {I"session_id:ETI...` – Sergio Belevskij Mar 29 '16 at 06:05
  • Additional question about this - once Rails does encounter a bogus session, does it delete it so that the same user doesn't repeatedly cause the same error? i.e., if I wait, will the problem just go away, or am I going to be forced to put in this change? :) – Hakanai Jan 23 '17 at 22:05
11

If you're comfortable with changing your secret key, then it will solve the problem, and I can confirm that people with old cookies will not encounter a 500 error.

Run rake secret to generate a new secret.

If you've implemented config/secrets.yml, put the new secret in there. Otherwise, if you still have your secret in config/initializers/secret_token.rb, put it in there.

Leave your config/initializers/session_store.rb file alone -- you don't need to change it.

In config/initializers/cookie_store.rb, change it to :json:

# Be sure to restart your server when you modify this file.

Rails.application.config.action_dispatch.cookies_serializer = :json

I can confirm that this works, even when your browser is storing an old session cookie. By changing the secret, when someone with an old session cookie visits your site, the server simply ignores the old session state and creates a new session. No 500 error.

ctc
  • 2,640
  • 1
  • 16
  • 18
2

I just had the same problem and used the answer here and all was fixed. After reading the comments though I found that just changing the secret also fixed the problem, as it should I suppose.

I think changing the secret is a better solution to the problem than switching to :hybrid like @Thibaut Barrère stated in the comments

doz87
  • 591
  • 6
  • 15