Detect When a Devise Session Expires

Rails/Devise - Determining when user session will expire

Here is how you do it:

class User < ActiveRecord::Base
devise :authenticatable, :timeoutable, :validatable, :timeout_in => 20.minutes
end

How to get Devise session timeout callback?

I found that doing Warden.before_logout was the best solution:

# app/models/user.rb

Warden::Manager.before_logout do |user, auth, opts|
#fdsafdsafdsa
end

Unfortunately, there doesn't seem to be any way to do this with pure Devise.

Why does devise redirect to current path when session times out

After a long "debugging weekend" I found out that the issue was because the Session and Cookie middlewares were placed after Warden in the rack stack.

My application is a Rails 5 API application, which means cookies and sessions are not available by default. Despite being an API app, I had to incorporate session / cookie based auth mechanism for certain reasons. So I manually added the two middlewares to the rack stack.

Since I added them in config/application.rb they got added almost at the far end of the stack, i.e. much after the Warden middleware itself. However the Warden middleware makes it very clear that it needs a Session and Cookie manager before it in the stack. That way any session changes it makes will get serialized into the session and the cookie eventually.

This resulted in the session changes done by the failure app being discarded. Because of that the session never got cleared and resulted in a redirect loop. The following steps will make it clearer.

How it should have been

  1. User logs in. Session is set with user id.
  2. User uses. Session is updated with user id.
  3. User idles (at least for timeout period)
  4. User makes a request. Request is sent with same session.
  5. Session is identified as timed out. Clear the session and redirect back to same page.
  6. Browser visits same page again.
  7. No user in the session. Redirect to login page.

How it happened in my case

  1. User logs in. Session is set with user id.
  2. User uses. Session is updated with user id.
  3. User idles (at least for timeout period)
  4. User makes a request. Request is sent with same session.
  5. Session is identified as timed out.
  6. Session is cleared but the cleared session is never serialized back to the cookie. (This happens because in case of auth failure control goes directly back to Warden middleware bypassing all the intermediate middlewares it came through. So it misses the cookie and session middlewares)
  7. Redirect back to same page. Browser keeps the session cookie unaltered.
  8. Browser visits same page again with the same session cookie

Steps 5-8 repeat until browser stops with an error.

Here is a sequence diagram I made capturing the whole flow for anyone interested in the details.

Devise Timeout Flow

@Prometheous : Thank you for your comment. However one thing is still unclear to me :

In case of a timeout, what issues will be there if the FailureApp directly redirects to scope login url. You say :

Without the redirection to the attempted path, devise wouldn't know
how to redirect to the sign in page.

But, can't it get it from the scope_url method which is used in the else part here : https://github.com/plataformatec/devise/blob/master/lib/devise/failure_app.rb#L128 ?

scope is known for sure.

What am I missing?



Related Topics



Leave a reply



Submit