lynndylanhurley / devise_token_auth

Token based authentication for Rails JSON APIs. Designed to work with jToker and ng-token-auth.
Do What The F*ck You Want To Public License
3.52k stars 1.14k forks source link

Unable to destroy HttpOnly cookie when token expired in cookie_enabled mode #1631

Open justindoran opened 3 weeks ago

justindoran commented 3 weeks ago

When cookie_enabled is set to true and tagged with HttpOnly, devise_token_auth will result in a broken session state. This is because the SessionsController is unable to delete the cookie if the user variable doesn't get set (line 55 of the SessionsController). The user variable not being set would happen under routine circumstances, such as when the token expires (i.e. a user comes back a month later), thus making the resource instance variable being nil.

When devise_token_auth is operating under "normal" token mode, this isn't a problem, because the token could be programmatically deleted (by a javascript frontend clearing localstorage, say) and the end user could then be redirected to login again. However, in cookie_enabled mode with HttpOnly (I would imagine a common setting for security reasons), the frontend can't handle this and devise_token_auth will be left in a broken state: it tries to set the user by reading the token from the cookie, the user doesn't get set because the token is expired, and it returns an error without deleting the cookie. This repeats indefinitely due to the cookie being handled by devise_token_auth, but not being destroyed when it's invalid. Resolving the broken login state requires the end user to clear cache or delete the cookie manually.

The solution to this would seem to be having devise_token_auth delete the cookie at a different point in the controller flow, but I'm not familiar enough with the gem to identify precisely where that should happen without producing side effects. My guess would be that this is an unintended consequence of the first line of the SessionsController destroy method trying to avoid the session reset, when it actually should be allowing the session to reset when cookies are enabled: # remove auth instance variables so that after_action does not run user = remove_instance_variable(:@resource) if @resource