From the box Devise has 2 options to manage sessions:
rememberable utilizes database to store the time when user was signed in and compares it with current time - if the difference is more than config’s
remember_for setting the user will be signed out.
timeoutable first checks if rememberable is being used and not expired, then compares current time with last user’s request time - the difference is then being compared with config’s
timeout_in setting. What if you want to have multiple
timeout_in settings for different cases?
Well, there is an existing solution in
devise wiki: How To: Add timeout_in value dynamically. The idea is to override
timeout_in method in the
User model, if it’s enough for your purposes you can stop reading here. In my case I wanted to have a different session time based on the url which user uses(long session for regular application sign in, short session for embedded app version), so the implementation should be independed from
User model. There is no built in solution for this case in
devise, so I decided to build my own.
First of all, I checked warden manager in devise for timeoutable and removed this feature from the
User model to implement my own. Here is how it looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
All that’s needed to manipulate the session time is to use 2 session parameters:
last_request_at, which is being updated on each request and
session_valid_for which I set up during login in
SessionsController#create. I used a
super call with a block to make it work:
1 2 3 4 5 6 7 8 9 10 11 12 13
In order to respect SRP, I moved session time related logic into separate service, but of course the easiest way is to set it explicitly like
session[:session_valid_for] = 5.minutes/1.hour or using environment variables:
session[:session_valid_for] = ENV['session_time_short]/ENV['session_time_standard'].
One remaining issue is that existing signed in users don’t have
session_valid_for variable in their sessions, so they would never be signed out. The easy fix is to set it in
before_filter which is being executed before any call to any controller action:
1 2 3 4 5 6 7 8 9 10 11