How to update user password in Cognito user pool without old password using Amplify? - amazon-cognito

We have multistep register form where user can set their password in step 2.
(User register should happen in step1 itself) So, we will set random password during step 1 and registering user details in Cognito user pool.
But end user submitting actual password from step 2.
Cognito will not update password (from step 2) without sending old password (random generated from step1). Cognito considers this process will be password update.
So how we need to handle this situation? or Is there any option / tricks which amplify provides to overcome this case?

More context is needed to fully understand why a random password is necessary for the user in this situation.
For example, if you are trying to create a multi-screen signup process and you don't want the user to get to the end of the process only to find out their password doesn't meet standards, e-mail already exists, etc., it may be more conducive to the user experience to check if the user already exists in the user pool first using ListUsers, collect the data as they move through the steps, and finally call the SignUp API call.
While I would highly recommend reconsidering the approach taken, the AdminSetUserPassword is a backend API call that can be used to set a permanent password for the user, although extreme care should be taken with this method to prevent the API call from being used maliciously on another user.

Related

Adding Cognito users from our application Users page

I have my own Users page in my application where user Admin can create a new user.
I do not want to let the user sign up by himself, but have the admin of the system add this user.
What do you think the flow for that should be ?
I thought about:
create a new user with username and temp password in the users page.
The user gets an email and presses a link to confirm the email.
The user goes to the login screen of my application and inserts the username and temp password.
the login page changes to Change password so the user will insert the password and confirm the password for him.
when pressing login the user logins to the system.
I cannot find a best practice for adding a new user from a built-in users page in the app.
Do you think my flow is reasonable?
Do you have any code that I can use for that?
This is pretty close to the flow which Cognito has for admin-created users by default when using the Amplify UI Authenticator component. The only difference is that the temporary password is sent to the user via email, so the admin never needs to see it.
To achieve this, you need to use the AdminCreateUser action. The way you do this will vary depending on the library you're using to communicate with Cognito. If it's Python, you can use boto3. If it's JS, you can use the AWS JS SDK. (Sample code in this GitHub comment.)
It's not required to use Amplify UI, you could write all the pages yourself. But it works well with very little effort and looks quite professional. So it should be the first thing you try. Here's another answer providing sample code for React.

AWS Amplify/Cognito- a way to set TOTP MFA on first time user login only

I'm setting up an authentication where MFA is not optional, which means from the very first login attempt after registration, the user will be asked to set up MFA (in this case I will be using Time Based One Time Passcode, or TOPT). For this, I can see that following steps would be reasonable:
1)Get user information via the login form - Auth.signUp()
2)Determine from the user data retrieved in step 1) whether TOPT-based MFA is set for the user already. If not, go to step 3) or else step 4)
3)If TOPT is not set, redirect to a form where a QRCode will be generated in order to set up this MFA feature. After verifying the code, log the user in.
4)If TOPT is set, ask for the passcode. After verifying, log the user in.
My dilemma: It seems I cannot get the information in Step 2), i.e, whether TOPT-based MFA is set for the user already without the user already being authenticated. The flag challengeName retrieved in the payload via Auth.signUp() in step 1) only gives me info on whether MFA is enabled or not ('MFA_SETUP'), and not whether TOTP-based MFA has been set up already. For that, the method Auth.getPreferredMFA() is what would do the trick, but it only works if the user object being passed to it represents an authenticated (or already logged in) user. Is there a way to determine if TOTP MFA is set up for a user trying to log in (but not logged in yet)?
Also, any other solutions to tackle this problem would be welcome. There must be somebody out there who has run into the same scenario I have, where MFA is mandatory from the first log in itself.
I am facing the same issue. If the MFA is required, I open up a modal to get QR code displayed and setup the mfa for the user.
code: "NotAuthorizedException"
message: "Invalid session for the user."
name: "NotAuthorizedException"
But getting this error because the user hasn't logged in and created any access token yet.
My idea of solving this is actually logging in the user but making their permissions to not go beyond the SetupMFA screen so they only gain some permissions when they have completed the setup.
Have you made any progress yourself? I'd like to hear any solutions.

How to prevent concurrent login for a web application using express-session

I am creating a web application which will be used by App's Administrators and for security reasons we don't want to allow multiple active logins from a single user at any point of time.
I am storing session data in the web browser's cookie and want backend to have active user's information who are currently logged in to the application so that on successful login request I can find out if this particular user already has an active session. If that is possible then I can block the login for that user.
One way to do that is storing IsLoggedIn in the Database with LastLoginTime and on each login, I can use this two flags to identify if an active session exists.
Open to other better solutions if any
I think a more robust solution than checking last login times would be to generate and store an id for each new login and then include a middleware to make sure the session's id for each user matches what you expect. That way every time the user logs in on another device the previous one will be invalidated and only one session will be valid at a time. You may even just be able to use express-session's req.session.id.

External Login Account vs. Native Login Account

I am brand new to Visual Studio 2012 and MVC 4, and I've been working with the SimpleMembershipProvider via the WebMatrix.WebData library.
I'd like to integrate Facebook as an external login source down the road, but it's not a requirement as of right now. However, to get a decent feel for what it would take, I've been following the tutorial and guide found here - http://www.asp.net/mvc/tutorials/mvc-4/using-oauth-providers-with-mvc.
My question :
If a user has already been created using :
WebSecurity.CreateUserAndAccount(model.Email, model.Password);
WebSecurity.Login(model.Email, model.Password);
Can they be "upgraded" to an oAuthMemebership account in the future, if they choose to use their Facebook credentials instead of the email and password they created when first signing up?
I couldn't find a clear answer to this question in the guide, or elsewhere, so I'm hoping someone can clarify how that process may work.
The SimpleMembership setup allows for a local and multiple OAuth logins all sharing the same UserProfile - so a single user can login with either a local password, or FacebOogLiveWitter.
(I should state, that I'm assuming in this answer that the OAuth provider does not send back a matching piece of information for a local account. If they do then the principles of actually performing the merge are the same, but the complexity and steps are vastly reduced.)
The OAuth registration process will refuse the user if they use an existing user name, rather than try and merge two accounts. Therefore this isn't simple, you'll have to build the functionality yourself. The process is complex as there are many directions the user can approach this from (so you could simplify by only supporting one or two), and you need to enforce security as well in case someone tries to merge into an account they don't own.
I will assume you are comfortable with the link you've posted, and you've followed the Facebook help at (for example) Facebook Login and The Login Flow for Web (without JavaScript SDK) so you have a working test application.
Your general process has to have multiple user journey approaches to make sense to a user:
for a logged in user (with a local account)
let them login to facebook and associate the accounts
let them merge an existing account on your site which uses a facebook login
for a logged-in user (with a facebook account)
let them create a local account
let them merge an existing local account on your site
for a non logged in user who tries to register a local account
let them merge this new account with a facebook login that is already registered, and do that as part of the registration process
for a non logged in user who tries to register (or log in for the first time with) a facebook account
let them link this with an existing local account as part of the registration process
etc.
ASK PERMISSION
(You can skip this if the OAuth provider has sent back a matching identifying piece of information, such as an email address).
You should enforce confirmation security, usually through email confirmation sent to the target account of the merge. Otherwise:
someone can login to your site with facebook for the first time
during that process say they "own" the email address or username of a local account (remember, facebook won't necessarily confirm what their email is for you)
and therefore gain access to the existing local account
So, once the merge "request" is made, you need to ask for permission to proceed from the target account of the merge.
The MVC 4 AccountController
I will use Facebook as our OAuth example. To compare what happens when you register a user on your local authentication framework vs. OAuth:
Local: creates an entry in webpages_Membership and an entry with the same UserId in UserProfile (assuming you are using the default tables for the MVC 4 application template)
OAuth: creates an entry in webpages_OAuthMembership and an entry with the same UserId in UserProfile
Now let's look at what happens when a user signs in using Facebook for the first time:
They click on Login using Facebook (or whatever your button says)
they get taken to facebook to login
they succeed (let's assume that, and ignore the failure case)
they then get sent, invisibly to them, to /Account/ExternalLoginCallback
OAuthWebSecurity.SerializeProviderUserId is called, passing the OAuth details to that Action
They get redirected to /Account/ExternalLoginConfirmation and asked to provide a username for their new presence on your site
If that user name is available then UserProfile and webpages_OAuthMembership entries are created
This process is your chance to "join" the accounts by matching some unique piece of information. As long as you end up with the same UserId in UserProfile, webpages_Membership and webpages_OAuthMembership you should be ok. So we have to intercept the process at the point of /Account/ExternalLoginConfirmation.
If the OAuth provider has sent back a matching identifying piece of information, such as an email address, this becomes simple, test for this in the ExternalLoginConfirmation action, and auto-merge using a similar process to the one outlined below.
However, I think you can't/shouldn't assume that the user uses the same email address for your site and OAuth, (nor should you for many reasons). Also, probably in the T&Cs for something like FacebOogLiveWitter it stops you asking for the email of their account anyway, and if they don't currently they might in future.
So instead, you could link the accounts based on alternatives, like username or email address, or phone number. Either way you are going to need them to input some identifying piece of information that is unique against an account, and will pull back the target account.
Wrapping up
So to put this all together: In the first part of this answer I outlined how you will need to consider multiple user journeys to merge accounts. I will use the example 4.1.
Your process will need to:
(Assumption - when a user first registers with a local account, you ask them for an email address and validate it or assume it is valid)
Let the user login with facebook for the first time
at Account/ExternalLoginConfirmation ask them if they want to
Create a new account with you
Use their facebook login to access an existing account
Assuming the latter, then you log a request in a new table (maybe "MergeAccountRequests") with:
The facebook account UserId
The target merge local account UserId
An authorisation code to use in the email you need to send
(From this point on, if they login without confirming that merge, they will have to get sent to a page to ask them to confirm, rather than create objects in other db tables which you have to worry about later)
You then send an email to the address of the target merge (local) account asking for permission to complete the merge (a standard confirmation email, with a link)
When they click on that link, or enter the code you sent them (you could use SMS as well as email) then you need to merge the two accounts
Choose the "new" and "target accounts (in this case "new" is the facebook account as you don't have data associated with it yet)
Delete the UserProfile of the "new" account
Change the UserId of the "new" account webpages_OAuthMembership table to the same as the "target" account
Log the user out (so there are no complications depending on which account they are currently logged in with)
Display a message to the user telling them the merge is almost complete and that they can now log in with either account to confirm and complete the merge
Rather than send them to a login page, i would give them the login options alongside the confirmation message.

Should password reset pages automatically authenticate users?

Many lost password workflows usually result in a page which is reached by a temporary link emailed to the user. This link then takes them to a page that asks for a new password.
Upon entering the new password should a user be forced to logon manually, or should the password reset page authenticate the user automatically which would reduce the number of steps and thus complexity of the process for the end user?
I often encounter password reset pages that make me reset my password and then login which feels like I'm logging in twice for no good reason.
I quite like drupal's method: The user gets sent an email with a link in it which will log them on once; upon logging in with it they are given the opportunity to change their password.
I don't know of any significant advantage to forcing the user to re-enter the password that they just entered twice. If someone does, I'd be interested to hear about it.
You should make it auto login. Don't see why you would make the user login.
If it's because of bot protection, just add a captcha when the user logins using the link.