codahale.com٭blog

This is my old blog. My current writing is here: codahale.com

Dynamic session expiration times with Rails

One of the problems with Rails that I’ve been running into recently deal with sessions–they never seem to last long enough. For long-term data, cookies are appropriate, but for an app I’ve been working on I wanted users to be able to return to their state even after a few days.

Setting the expiration date for session cookies isn’t particular difficult in Rails: pass a Time object in your config/environment.rb and you’re off and running. That works if you want your sessions to expire in two years, say, but what happens if you want your sessions to expire in a week? Wouldn’t Time.now + 1.week work? No, because the environment code is executed just the once, and unless you’re kicking your FastCGI processes over every day or so, your app will eventually be serving up session cookies that expire last Tuesday. And that’s bad. So what’s a boy to do?

Write a plugin, that’s what.

Dynamic Session Expiration! A Plugin! For Rails!

Here we go!

Installation

Got your project under Subversion source control like a good little railer?


./script/plugin install -x http://svn.codahale.com/dynamic_session_exp/trunk

Don’t use Subversion, because source control is for weaklings?


./script/plugin install http://svn.codahale.com/dynamic_session_exp/trunk

Configuration

Now, let us away to the config/environment.rb!


CGI::Session.expire_after 1.month

This does pretty much exactly what it looks like. Session cookies are served up with an expiration date set to one month after the current time.

Conclusion

I’m a little concerned that maybe there’s some really graceful way of getting Rails to deal with session cookies a bit better, or that maybe I’m ignoring some really reasonable design spec in doing this, but hey. I need this functionality, so here it is. And it’s here for you too if you need it. I haven’t written any documentation for this because it’s so damn simple.

(FYI, this is copyright © 2006, but released under the generous and humane terms of the MIT License, copies of which can be found in various places throughout the intarweb. Bombs away!)

31 Responses to “Dynamic session expiration times with Rails”

  1. Ken Collins Says:

    Great job, this is exactly what I needed too. I am just learning with a little project that I started using the “login_engine”. My goal was to have users that return to the site, refresh their cookie’s expires setting 30.days.from_now and that is exactly what appears to be happing now. I have tested this on WebBrick and Apache2/FastCGI but not in production mode yet.

    Will the cookie refresh in production mode too?

  2. Coda Says:

    If you have it configured like so:

    
    CGI::Session.expire_after 1.month
    

    in your config/environment.rb, then it’ll serve up session cookies that expire in a month’s time in all of your environments.

  3. LeRoi Isaacs Says:

    I’ve tried implementing this in a current App. It works fine on WinXp. It works fine with FireFox. It even works fine with IE.
    But when i try to run on Unix, lighttpd, IE stops working.
    For some reason, on unix, when IE is talking to the app, the sessions become transient. Every page request causes a new session object to load up. So the expiry becomes meaningless, since you can’t remain logged in. I’m at my wits end, as to why this happens only on this combination, when unix/firefox, works fine…

    Regards.

  4. Coda Says:

    Jeez, LeRoi, that’s a strange problem you’ve found. I can’t duplicate it, either. I’m running lighttpd 1.4.11, and even accessing it via Internet Explorer 6 works fine, sessions and all.

    (Well, not totally fine–I haven’t done the requisite CSS skullduggery for IE on this project yet, so it looks like a Mondrian painting. But the sessions work fine.)

    Maybe check the IE6 settings?

  5. 10 cool Rails plugins by Coda Hale Says:

    [...] dynamic_session_exp [...]

  6. Kingdom Solutions Says:

    This looks great, thanks Coda, it’s just what I need. Simple setup too!

    Dan

  7. RJB Says:

    Simple. Exactly what I needed. Thank you!

  8. Joe Goggins Says:

    Does this plugin automatically clean up the temporary ruby_sess files that ruby on rails generates as well? I assume that this is ordinarily left up to a cron job of some sort that periodically goes through the session file directory and wipes out old session temp files.

    A good solution, baked into Ruby on Rails, would be great, does one exist?

    Joe G

  9. Coda Says:

    Joe–No, it doesn’t, there isn’t really a good solution yet. Move your sessions to the database as soon as you can and set up a cron job to clean out old sessions.

  10. saush.com » Session expiry in Rails Says:

    [...] My solution? I removed session expiry, such that the session doesn’t expire. This means that as long as I don’t log out or close the browser, the session remains valid. So what are the other options? Unfortunately as I found out, Rails doesn’t really allow any easy means of doing dynamic session expiry. This entry in the rubyonrails wiki provides good information on the possible alternatives. Another alternative is suggested by Coda Hale in his blog. [...]

  11. TomY Says:

    I found the same problem that “LeRoi Isaacs” describe. Actually, I was running Webrick on Redhat. The IE can not stay login. It’s not about IE setting because I have try different machines, which those IE works with other server.

  12. Michele Says:

    I’d love to use this plugin, but I get a stack level too deep error. Anyone experiencing this issue?

  13. Amor is Love » Blog Archive » Gostei Disso (III) Says:

    [...] Quick note… using THESE INSTRUCTIONS, I made the session on gosteidisso.com stick. Now users once they login they will stay logged in even if they close their browsers. The beauty of this particular setup was that I got it working without writing a single line of code… COOL! [...]

  14. Tony Stubblebine Says:

    Thanks Coda. Worked great with one gotcha on my side, gotta put the expire_after statement at the bottom of environment.rb. Makes sense but maybe worth noting above.

  15. Edham Arief Says:

    Faced the same problem like Tony, had to put the expire_after statement at the bottom of environment.rb. Anyway it worked fine after that :)

  16. Ken Collins Says:

    Coda… a year into programming almost by the date of my 1st post and I am still using the extension quite often. I rewrote it a bit today for a new project. Maybe if you like it you can update the repo.


    class CGI
    class Session
    cattr_accessor :expire_after
    alias :initialize_without_dynamic_session_expiry :initialize
    def initialize(request, option={})
    option['session_expires'] = Time.now + self.expire_after if self.expire_after
    initialize_without_dynamic_session_expiry(request, option)
    end
    end
    end

  17. linoj Says:

    I’m wondering what would it take to modify the plugin for expiry options on a per-user basis? in my case, I have different roles with different security requirements.

  18. 進・日進月歩 » rails: railsはセッションのexpireが動的に設定できない。 Says:

    [...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ [...]

  19. 進・日進月歩 » rails: railsはセッションのexpireが動的に設定できない。 Says:

    [...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ [...]

  20. Trail Blog » Blog Archive » Rails开发中“remember me”实现 Says:

    [...] me功能的代码。取而代之的是我找到了两种不同的解决方案一种是set all session to be persistent 另外一种是 additional long-term state on the server [...]

  21. bobc Says:

    I’ve seen the same issue as LeRoi Isaacs and TomY above. We are using Linux Fedora, mongrel, apache and IE 6.0/7.0 seems to lose session state, meaning every request creates a new session, thus the user is not able to login (because there is no session persistence). We have not identified what is the culprit in this scenario.

    But it has something to do with setting the session_expires in Rails:
    Ex.
    ActionController::Base.session_options[:session_expires] = 1.year.from_now

  22. Heitzso Says:

    I used the subversion command to install directly into my svn tree, but that left the external svn referenced within my svn tree. So now, when I run ’svn update’ both my tree and this tree get updated. That’s awkward but livable. But I’m not seeing any clear instructions on HOW TO DELETE this from my svn tree. ’svn delete …’ followed by ’svn ci -m ” ‘ does not work to delete this alternate svn repository within my svn repository. Help would be appreciated. Thanks.

  23. Coda Says:

    Heitzso: Edit the svn:externals property for vendor/plugins. The Subversion project has a free book which is a great resource for learning more about how Subversion works.

  24. Steve Says:

    This works great for me but we want to allow the user to decide how long the session is valid. Kind of like how Yahoo mail lets you check a box during sign ‘Keep me logged in for 2 weeks’. If they don’t check that box then the session should only be good while their browser is open and then only for a much shorter duration, possibly a few hours.
    Is there a way to do allow a person to set the session expiry when a user logs in?

  25. pstradomski Says:

    Your solution does not allow one to set this on per-controller basis (as it uses class variables). I use sligthly different approach (similar to the one used Ken Collins above, although I didn’t find it when researching the problem earlier):
    http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/

  26. Chan Says:

    hi
    i’ve installed the plugin and modified the environment.rb file.
    however when i restart the server, i’m getting this error message.
    ./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:477:in `const_missing’: uninitialized constant CGI::Session (NameError)

    is there something that i missed out?

  27. Things I commonly do when starting a Rails project « The Tao of Adam Says:

    [...] DynamicSessionExp [...]

  28. eXpand yOur cReativity » Blog Archive » Ruby On Rails Security Guide Says:

    [...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ http://www.onrails.org/articles/2006/02/18/auto-login http://livsey.org/2006/6/30/persistent-logins-in-rails [...]

  29. Juo Says:

    Hi was the problem with IE sessions expiring (as posted by LeRoi Isaacs and TomY) ever resolved? I am having the same problem using mongrel on ubuntu. Similarly, it works fine on other browsers, but I can’t get a valid session using IE. Interestingly, it produces 2 session files as opposed to just one using the other browsers.

    Thanks if you can help, I’ve tried everything…using this plugin, setting expiry, switching to db store of sessions, etc.

  30. Juo Says:

    Hi again, I just tried setting the Privacy Settings from Medium to Low in Internet Options, and this resolves the issue.

    Is this not a common problem with Rails applications? This could not be the most ideal fix. Could it be that by default Rails cookies are not as secure as they should be, and theres something else I’m supposed to do on the server? Surely not, I’m obviously doing something wrong, but I can’t see what. Anyone care to offer advice?

    Would it have something to do with *nix and IE permissions not compatible? The session file permissions are u=rw only, so that should be ok.

  31. Ruby On Rails security guides | eXpand yOur cReativity Says:

    [...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ http://www.onrails.org/articles/2006/02/18/auto-login http://livsey.org/2006/6/30/persistent-logins-in-rails [...]