set timeout for a token in rails - ruby-on-rails

How do i set a timeout for a given authentication token? After the timeout, the token will be deleted and the user won't be able to use it on his requests.
I'm using rails 3 and devise.

I was looking for this feature too, but didn't find a way to do it directly.
You can reset the authentication token on each sign-in and use the rememberable in-between:
in your application controller, in after_sign_in_path_for():
resource.reset_authentication_token
in devise.rb:
config.remember_for = 1.day
Or you can create a cron-job to periodically clear the invalid authentication_token entries from the users table.

I'm not sure if that's exactly what you are looking for, but this is a simple option in Devise.
If you set the following option in config/initializers/devise.rb
config.timeout_in = 30.minutes
then Devise will expire the token after 30 minutes of inactivity. The same operations that Devise does for session authentication should also work with the authentication_token.
I have used that in my current project and tested it using Timecop gem:
it "should timeout without activity after 30 minutes" do
auth_token = #user.authentication_token
get "/frontend/users/#{#user.id}.json?auth_token=#{auth_token}"
response.status.should == 200
Timecop.travel(45.minutes.from_now)
get "/frontend/users/#{#user.id}.json?auth_token=#{auth_token}"
response.status.should == 401
Timecop.return
end
Also, I don't believe that the token follows the same analogy as user/password combination as mentioned in one of the comments, since you wouldn't store your password in plain text but you do with your token. I would recommend resetting the token after each logout as well.

At devise initializer file
#/config/initializers/devise.rb
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again. Default is 30 minutes.
config.timeout_in = 1.day
# If true, expires auth token on session timeout.
config.expire_auth_token_on_timeout = true

Related

Rails - Devise - Disable Reset Password Token expiration time

I currently working on a Rails app with devise authentication. I need to disabled the token expiration for reset password. According to Devise Documentation on Recoverable there is not configuration to do that. The only method I think to make this works is to override Recoverable and the reset_password_period_valid? function to always return true. But I not sure if is the best/proper solution.
Current on my devise.rb I have:
# ==> Configuration for :recoverable
#
# Defines which key will be used when recovering the password for an account
# config.reset_password_keys = [ :email ]
# Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to
# change their passwords.
config.reset_password_within = 2.hours
You can set it as 10 years, for example, and it will be like disabled token expiration.

Rails/Devise - how to logout a user after an `x` minutes of inactivity?

I am developing a system which contains many roles and one of the roles is ADMIN which can access critical part of the system, I want to limit the user's session which when he/she don't interact with the system for certain period of time, its session gets expires and the next time he/she should log in again, How can I do this?
Devise has a timeoutable module that you can use.
In your User model you would include :timeoutable with your devise models and in the devise.rb initializer you would configure it comparable to:
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again. Default is 30 minutes.
config.timeout_in = ENV['YOUR_TIME'].to_i.minutes
If you want to be more flexible with your user types you can add a method something like this for your User model:
def timeout_in
if self.type == 'Admin'
45.minutes
else
60.minutes
end
end
That would be used instead of setting timeout_in in your initializer.
Edit: My first response was similar to the first answer in the thread below, but the second answer in that thread might be a better fit. Since it works directly with the session_store.
Here's a useful StackOverflow link that can provide extra info: Rails 4: Session Expiry?
This documentation has some info on the methods available for session manipulation: http://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html

Rails cookie based sessions: mixing session scope with expiration times

So I've asked this question in a different way here and got no answers so I'm going to try to rephrase it, since this seems to be a very simple issue.
I have a Rails app with cookie based sessions. By default they don't have any expires_at timestamps and so the scope of the session cookie is 'session'. This is your vanilla Rails sessions stuff.
Now I want to create a 'demo user' functionality wherein I kick the user out after 15 mins. To accomplish this, I want to set an expires_at on the session cookie for Time.now + 15.minutes
session[:expires_at] = Time.now + 15.minutes
Now this above piece of code does execute, but it has no impact on the cookie's scope. The scope remains 'session'. How do I change the scope from being 'session' to being a datetime?
If I configure my entire application's Session in the production.rb to be
:expire_after => 24.hours
Then it will work... but the problem is that I want to selectively control the expiration date on the session cookie.
Edit: Turns out that the reason why there is no impact on the cookie's scope when I set the session[:expires_at] is because subsequent requests are clobbering the session cookie and resetting it back to session. Still not sure what to do about it.
Perhaps instead of relying on cookie expiry (see section 2.9 in "Ruby On Rails Security Guide" on why it is bad), similar to this answer, store timestamp when session was created in the session itself (say session[:created_at]) and then check on each request if it needs to be expired for these 'demo users':
before_filter :check_session
def check_session
# TODO: check session validity
if session[:demo_user] && session[:created_at] > 15.minutes.ago
reset_session
# TODO: redirect to login page
end
end
While not the very elegant way, but this works for a single session:
...
request.env['rack.session.options'] = {expire_after: 15.minutes}
session[:user_id] = 1
...

Devise Remember Me and Sessions

I'm confused with the devise gem config settings:
# The time the user will be remembered without asking for credentials again.
config.remember_for = 2.weeks
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again.
config.timeout_in = 10.minutes
I want to have a user select the "Remember Me" checkbox (i.e., keep me logged in), but the default session timeout is 10 minutes. After 10 minutes it asks me to log in again even though I have clicked "Remember me". If this is true then the remember_for is really meaningless. Obviously I'm missing something here.
Ryan is correct in that the default Devise gem does not support both the :rememberable and :timeoutable options. However, like all things Ruby, if you don't like the decision that some other coder has made, especially when it strays from the norm that most users are likely to expect, then you can simply override it.
Thanks to a (rejected) pull request we can override this behaviour by adding the following code to the top of your Devise config file (/config/initializers/devise.rb):
module Devise
module Models
module Timeoutable
# Checks whether the user session has expired based on configured time.
def timedout?(last_access)
return false if remember_exists_and_not_expired?
last_access && last_access <= self.class.timeout_in.ago
end
private
def remember_exists_and_not_expired?
return false unless respond_to?(:remember_expired?)
remember_created_at && !remember_expired?
end
end
end
end
This will now allow you to configure both options and have them work as you would expect.
config.remember_for = 2.weeks
config.timeout_in = 30.minutes
The timeout_in will automatically log you out within 10 minutes of inactivity and is incompatible with the remember_me checkbox. You can have one, but not both.
The information in previous answers is outdated. I've tested my project, which uses Rails 4 and Devise 3.5.1 and also checked devise code to be sure.
Now it looks whether Remember Me checkbox was checked:
if yes, it checks if remember_exists_and_not_expired, so basically uses config.remember_for for session management
if no, it checks if last_access <= timeout_in.ago, using config.timeout_in correspondingly

Using devise "rememberable" without cookies

I have a working Rails site that uses devise to manage users. For session management, I am using devise's rememberable strategy, which stores and retrieves encrypted authentication information from a user's cookie.
I'm implementing a multi-photo upload widget that uses flash. Flash does not support sending cookies along with requests. This is a problem with multiple multi-upload flash+javascript libraries, so fixing this shortcoming is probably not feasible.
So my question is: can I successfully authenticate to devise/rememberable without using cookies? And if so, how?
More details
Devise/rememberable depends on the value of remember_token within the cookie. If I could fool Rails into thinking that the value was supplied as a cookie (e.g. request.cookies['remember_token'] = '...'), my problem would be solved. Devise/rememberable would find the correct value there, unpack it, and successfully authenticate. However, the request.cookies hash is apparently read-only. Writing to the hash is silently ignored. Example (debug console from an incoming POST request):
>> request.cookies['remember_token'] = 'a string'
=> "a string"
>> request.cookies['remember_token']
=> nil
>> request.cookies
=> {}
I'm using (or trying to use) the FancyUpload v3 widget.
How about overriding Devise slightly?
Based on Devise 1.2.rc something like this should work:
module Devise
module Strategies
class Rememberable
def remember_cookie
# your code to get the hashed value from the request
end
end
end
end
Alternatively, you could add a new (subclassed) strategy:
module Devise
module Strategies
class RememberableParameter < Rememberable
def remember_cookie
# your code to get the hashed value from the request
end
end
end
end
Warden::Strategies.add(:rememberable_parameter, Devise::Strategies::Rememberable)
Or, look into Token Authenticatable:
Token Authenticatable: signs in a user based on an authentication token (also known as
"single access token"). The token can be given both through query string or
HTTP Basic Authentication
There's more about it here:
https://github.com/plataformatec/devise/blob/master/lib/devise/models/token_authenticatable.rb
Good luck!

Resources