views:

2257

answers:

8

My Rails-app has a sign in box with a "remember me" checkbox. Users who check that box should remain logged in even after closing their browser. I'm keeping track of whether users are logged in by storing their id in the user's session.

But sessions are implemented in Rails as session cookies, which are not persistent. I can make them persistent:


class ApplicationController < ActionController::Base
before_filter :update_session_expiration_date

private

def update_session_expiration_date
options = ActionController::Base.session_options
unless options[:session_expires]
options[:session_expires] = 1.year.from_now
end
end
end

But that seems like a hack, which is surprising for such common functionality. Is there a better way?

Edit

Gareth's answer is pretty good, but I would still like an answer from someone familiar with Rails 2 (because of its unique CookieSessionStore).

A: 

@Leon: Sessions are implemented in Rails as session cookies, i.e. on the client side.

Michiel de Mare
+13  A: 

You should almost certainly not be extending the session cookie to be long lived.

Although not dealing specifically with rails this article goes to some length to explain 'remember me' best practices.

In summary though you should:

  • Add an extra column to the user table to accept a large random value
  • Set a long lived cookie on the client which combines the user id and the random value
  • When a new session starts, check for the existence of the id/value cookie and authenticate the new user if they match.

The author also recommends invalidating the random value and resetting the cookie at every login. Personally I don't like that as you then can't stay logged into a site on two computers. I would tend to make sure my password changing function also reset the random value thus locking out sessions on other machines.

As a final note, the advice he gives on making certain functions (password change/email change etc) unavailable to auto authenticated sessions is well worth following but rarely seen in the real world.

Gareth Simpson
Have a look at the improvement of the suggested article at http://jaspan.com/improved_persistent_login_cookie_best_practice which adds the "series" concept for better security.Also your description is not accurate:1) the author of your article suggests an one-to-many mapping table between user and cookie in order to avoid constantly invalidating your login when switching computers (i.e work and home)2) the invalidation of the random cookie will not cause what you describe (the two computers problem)
cherouvim
+1  A: 

This is a pretty good write-up of one guys experience of creating 30-day persistent sessions.

WARNING: blog post is from 2006

http://grahamglass.blogs.com/main/2006/05/rails_sessionsr.html

engtech
+2  A: 

The restful_authentication plugin has a good implementation of this:

http://agilewebdevelopment.com/plugins/restful_authentication

Jarin Udom
+1  A: 

Note that you don't want to persist their session, just their identity. You'll create a fresh session for them when they return to your site. Generally you just assign a GUID to the user, write that to their cookie, then use it to look them up when they come back. Don't use their login name or user ID for the token as it could easily be guessed and allow crafty visitors to hijack other users' accounts.

Teflon Ted
+1  A: 

I have spent a while thinking about this and came to some conclusions. Rails session cookies are tamper-proof by default, so you really don't have to worry about a cookie being modified on the client end.

Here is what I've done:

  • Session cookie is set to be long-lived (6 months or so)
  • Inside the session store
    • An 'expires on' date that is set to login + 24 hours
    • user id
    • Authenticated = true so I can allow for anonymous user sesssions (not dangerous because of the cookie tamper protection)
  • I add a before_filter in the Application Controller that checks the 'expires on' part of the session.

When the user checks the "Remember Me" box, I just set the session[:expireson] date to be login + 2 weeks. No one can steal the cookie and stay logged in forever or masquerade as another user because the rails session cookie is tamper-proof.

Daniel Beardsley
+4  A: 

I would suggest that you either take a look at the RESTful_Authentication plug in, which has an implementation of this, or just switch your implementation to use the RESTful Authentication_plugin. There is a good explanation about how to use this plug in at Railscasts:

http://railscasts.com/episodes/67-restful-authentication

Here is a link to the plugin itself

http://agilewebdevelopment.com/plugins/restful_authentication

Mattew
A: 

This worked like a charm for me:

http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/

Now my CookieStore sessions expire after two weeks, whereby the user must submit their login credentials again in order to be persistently logged-in for another two weeks.

Bascially, it's as simple as:

  1. including one file in vendor/plugins directory
  2. set session expiry value in application controller using just one line
Allan L.