Rails, devise: how to replace previous login via token authentication - ruby-on-rails

I use devise with module TokenAuthentication
And it is ok when I unauthenticated and I follow link with ?auth_token= part. Like this:
I follow link: /orders?auth_token=q2a8w6virARzv6B2C1vR where q2a8w6virARzv6B2C1vR is authentication_token of user1. And now I logged in as user1.
But when I logged in as some user via email\password and common sign_in page and then follow such link with auth_token with another user token I unexpectedly stay logged in as first user.
Like this:
I sign in via sign in page. I
fill in email and password of user2.
And now I logged in as user2
I follow link:
/orders?auth_token=q2a8w6virARzv6B2C1vR
where q2a8w6virARzv6B2C1vR is
authentication_token of user1. And I
still logged in as user2 instead of
expected user1.
Is it bug? And what is the best practices to change this behavior to force replace authentication via token?
Rails 3.0.6
Devise 1.2.1

you did uncomment :token_authenticatable in your user model, correct?

Let's do some question necromancy...
Before running stragegies (token_authenticatable, database_authenticatable) Warden first checks if user is already set in current session.
This happens in: https://github.com/hassox/warden/blob/3d653371a2ff594d9965c1dde642c98cd8485e15/lib/warden/proxy.rb#L212
Is action responding /orders query supposed to use only token auth? If so, you can add: before_filter: reset_session (before authorize_user) so that Warden failed to unserialize user from the session and was forced to perform authentication.
[EDIT]
This issue ticket contains reasonable solution: https://github.com/plataformatec/devise/issues/1644

Related

Invalidating Devise user session identifier after password update

Scenario: As an Administrator I need to invalidate a user's session (log them out) after I update the user's password. This is in accordance with best practices as per https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#Renew_the_Session_ID_After_Any_Privilege_Level_Change
I am using Devise and I saw here https://stackoverflow.com/a/45756884/664675 there is a config to log the user out: config.sign_in_after_reset_password = false
However, I have enabled this config in my devise.rb but the user remains logged in. Not sure why that is?
I am also using Redis as the session_store
Example::Application.config.session_store :cache_store,
key: '_example_session',
secure: true
Is it feasible to delete the particular user's session store from Redis upon Password reset by the Administrator? And if so how could I find their particular session key within Redis?
the flag sign_in_after_reset_password does not relate to logout user at all, sign_in_after_reset_password = false imply that in case a user update his account password by himself then do not automatically sign-in his account again, and that logic happen only on PasswordsController#update.
So you as admin try to change password of another user in a custom controller, of course it's not logout user no matter the value of sign_in_after_reset_password is.
devise use gem warden to logout user (in other word: destroy user session) and warden base on request session not base on database, that mean there's no way an admin can get another user's session to reset, so you can not force logout another user by only devise, you need to handle this feature outside devise (such as add session to user table or a devise hook something like timeoutable)
reference: https://github.com/heartcombo/devise/issues/5262
What you're looking for is the setting sign_in_after_change_password which you should set to false (it defaults to true). The method has a slightly confusing name – it means "should we sign the user in after changing their password" instead of "should the user have to sign in after changing their password".
References:
https://github.com/heartcombo/devise/blob/master/lib/devise.rb#L296-L298
https://github.com/heartcombo/devise/blob/c82e4cf47b02002b2fd7ca31d441cf1043fc634c/app/controllers/devise/registrations_controller.rb#L163-L167

devise_token_auth forget password API shows Use POST /sign_in to sign in. GET is not supported error

Following this solution https://stackoverflow.com/a/47761138/7818637 I am designing forgot password flow APIs on rails where I am using devise_token_auth gem for authentication.
1. A POST call to send a Password Reset Email
URL: http://localhost:3000/client/auth/password
form-data: {email: 'john#gmail.com', redirect_url: 'http://localhost:3000/client/auth/sign_in'}
2. A GET call to verify the password reset token (clicked in email)
I am receiving the the following URL on my console containing redirect_url and reset_password_token:
http://localhost:3000/client/auth/password/edit?config=default&redirect_url=http%3A%2F%2Flocalhost%3A3000%2Fclient%2Fauth%2Fsign_in&reset_password_token=ZBsx64Gk1VBraM3THZTn
When I call on this URL, I am receiving the following error:
Use POST /sign_in to sign in. GET is not supported.
What I have already tried:
Following the issue here I have found that I am already using include DeviseTokenAuth::Concerns::SetUserByToken in my controller.
Console Logs:
When the users clicks the url in your email you redirect them to /password/edit path. In this action you verify the user. If everything goes right the user will be redirected in redirect_url which is the sign_in path in your case.
You should change the redirect_url in your email and create an action and a view in which the user will be redirected. In this new view you will have the fields so the user can reset the password. Make sure that the new url will use 'GET'. On form submission redirect user to sign_in path so he/she can log in with their new password.
Please read https://devise-token-auth.gitbook.io/devise-token-auth/usage/reset_password for more info.

ActionController::InvalidAuthenticityToken when login using two devise model (user and admin)

I create an app using two devise model, user and admin.
I'm following the devise wiki from this link, I'm using the option 1
How To: Add an Admin Role
So I open two page at the same time, the user login page and the admin login page.
When I login in the admin login page it succeed but when I login on the user page it raise an error ActionController::InvalidAuthenticityToken same goes with the other way.
But if I refresh the page first then I login it will succeed.
Are they using the same AuthenticityToken? So when the admin logged in, the AuthenticityToken is changed so when I try to login with the user it raise an InvalidAuthenticityToken?
Thanks.
The behaviour you are seeing is expected.This is because the value of csrf token changes once you sign in,expiring the old value.
There is a workaround to disable CSRF protection for the sign_in action in the ApplicationController. Look here: https://github.com/plataformatec/devise/issues/3102

Rails, Devise: is it possible to only confirm email logins and not Facebook logins?

I have set up Ruby on Rails and Devise using code from here
Email logins and Facebook login were all working fine. However, once I configure :confirmable (which creates confirmation emails and user have to click on a URL), Facebook login no longer works. It says Completed 401 Unauthorized in the RoR logs, even though it managed to get a token.
Is there some missing configuration for this to work?
The token doesn't care. Devise only checks for the confirmed_at attribute.
But you can just override the confirmation for certain users.
In your user.rb model:
protected
def confirmation_required?
facebook_token.nil? # replace with your own logic.
end
I was looking at another article on stack overflow. I basically did a skip_confirmation! which is defined in Confirmable.

Rails: Auto-login already signed up user (Facebook/linkedin omniauth)

I am using Omniauth and Devise to implement social login (Linkedin and Facebook) on a Rails4 website.
I want to be able to auto-login to user who has already logged in before on the browser (Same as facebook does: http://facebook.com)
I understand that this could be done by placing a cookie on the user with their user id and then use that on landing page to login the user.
However I feel this is such a common use case that Devise or some other Gem might already exist that does it cleanly ?
Devise has a module Rememberable, which allows you to remember a logged in user.
Just add :rememberable to the devise method in your User model.

Resources