devise: sign_out doesn't properly clear cookie-based sessions
We have a Rails 4.0.5 app with Devise 3.2.4.
For some reason, when we call SessionsController#destroy, it correctly logs the current user out, but it does not correctly destroy the session when the OurApp::Application.config.session_store is set to :cookie_store. Installing the new activerecord-session_store gem and changing session_store to active_record_store resolves the issue.
Here’s the order of what happens:
- We
DELETE /users/sign_out. #destroygets called, and does seem to nuke the session.current_userbecomesnil, and Warden doesn’t know about any users. However, the session cookie is not removed from the browser.after_sign_out_path_forreturns thenew_user_session_url, just like we asked it to.- The page redirects to the
new_user_session_url. - We hit
SessionsController#new. However, Devise somehow thinks the user is still logged in, and treats them as such, by moving on to 6: after_sign_in_path_forgets called. This is the step that we know shouldn’t be happening, but we can’t figure out how it’s getting here. It should never get called, because the user was logged out in step 2 above.
With the :cookie_store, if we manually delete the session cookie from the browser and then hit the #destroy endpoint, it works. If we use the active_record_store, none of this happens. It behaves as expected.
I’ve tried reverting to several previous Devise versions to see when it was introduced, but the behaviour is the same all the way back to 3.
If I can provide any more information to help in troubleshooting, please let me know. We’ve tried stepping into and all the way through the Devise code and nothing is jumping out at us.
About this issue
- Original URL
- State: closed
- Created 10 years ago
- Reactions: 8
- Comments: 19 (5 by maintainers)
I found an article demonstrating a solution without having to change the storage:
You can add a session_token column to your devise model (e.g. User) and override Devise #authenticatable_salt method to contain your session token:
Now you need to invalidate the session cookie by resetting the session_token of a user on logout:
I hope that helps.
Isn’t this bad though? Shouldn’t this be fixed so cookies are invalidated on the server instead?
IMO this is not good at all. Have I missed something completely? Or is devise still expected to behave this way.
Yes, I know I can write my own stuff and store sessions in the DB or whatever but ideally Devise should handle this seamlessly. 😃
There is, use another session store instead of cookies.
No, we cannot handle this. This is the whole trade-off of using cookie-based sessions. They are replayable. Just use another storage if you don’t want this behaviour.
@sandipsubedi You’re right, this method isn’t working.
authenticatable_saltis only used when user logs in and whenrememberablemodule refreshes user session. It won’t be verified if user already has valid (or, well, stolen) session cookie.Devise already has
remember_user_tokeninvalidation mechanism based onremember_created_atcolumn. So there is no reason to add additional customsession_tokencolumn.Just use any store other than
:cookie_storeas José Valim suggested above.@trianglegrrl I think that it isn’t bug - take a look - http://maverickblogging.com/logout-is-broken-by-default-ruby-on-rails-web-applications/