Cannot reset password for users created in cognito console - amazon-cognito

Im creating a login for a CMS to a website for a small business using the React javascript framework. Obviously random people can't just register their own details so at present i am attempting to manually create the users (a max of 5 at present) within the cognito console. I have the majority of the authentication workflow established (using just the Auth library from Amplify) with INITIAL forced password reset, forced MFA TOTP authentication and successful access to the CMS on login. However the Forgotten Password functionality despite my best efforts just refuses to work and I believe I've narrowed it down to cognito itself.
Short of trying every damn combination of a user pool and created user to get this to work, I provide the following when creating a user from the cognito console -
1. Username (must be email)
2. Temporary Password
3. No phone or phone verification
4. Email and tick email verification
For the userpool conditions the following is the current working setup (minus the forgotten password functionality)
1. Email Address required for sign in
2. Standard attributes are given name, family name, phone number
3. MFA is required
4. Second factor is Time Based One Time Password
5. Email is selected as the attribute to be verified (which i believe to be a moot point as this is manually done when creating user)
6. No SMS role provided, required or necessary
7. I have verified an email address with SNS and have this entered in the FROM and REPLY-TO fields for email customization and have selected the use of using Amazon SES below these customization fields.
This is the entry point of my Authentication workflow, identifying where in the workflow the user is at and acting accordingly.
await Auth.signIn(email, password)
.then(user => {
setFetching(false);
switch (user.challengeName) {
case "NEW_PASSWORD_REQUIRED":
switchComponent("Verify", user);
break;
case "SMS_MFA":
case "SOFTWARE_TOKEN_MFA":
switchComponent("ConfirmSignIn", user);
break;
case "MFA_SETUP":
switchComponent("MFASetup", user);
break;
default:
history.push({ pathname: "/" });
break;
}
})
Everything works as it should for the most part. MFA workflow displays a nice QR Code for the user to utilize and confirm using their Authenticator of choice, NEW_PASSWORD_REQUIRED is submitted via the following -
const handleSubmit = async event => {
event.preventDefault();
if (noErrors()) {
setFetching(true);
await Auth.completeNewPassword(inputs.user, inputs.newPassword, {
email: inputs.email,
phone_number: inputs.phoneNumber,
given_name: inputs.givenName,
family_name: inputs.familyName
})
.then(() => {
setFetching(false);
switchComponent("MFASetup", inputs.user);
})
.catch(err => onShowDialog(err.message));
setFetching(false);
}
};
From what i can tell, nothing is out of the ordinary here. However any attempts to initialize the forgotten password flow after successfully authenticating past the REQUIRE_PASSWORD_RESET, even from the cognito console and i am presented with "Cannot reset password for the user as their is no registered/verified email or phone number", this is despite enabling the "verified email" when creating the user from the cognito console.
By using the aws command line I can force the verification however this to me is just infuriatingly unintuitive when the enabling of this when creating the user should take effect. Im at my wits end here and I have clients waiting for this software. Any help would be greatly appreciated in this instance. I apologize for any redundant content in this question I just want to make sure I cover everything the first time. Regards.

Related

Is a full sign-in required to verify a phone number using Firebase Phone Auth?

A question about firebase auth for authentication via phone number.
I was wondering if it was possible to link a "Phone Provider" to say a Google Auth Provider. There is no explicit mention of it in the docs.
The thing that had me scratching my head is - the Link Multiple Auth Provider docs talk about starting to authenticate with the new provider (phone provider) you want to link to the existing provider (google provider), but then stopping short of calling FirebaseAuth.signInWithXXX.
So in theory that would work like:
The user logs in via google (google idp provider)
The user kicks off the phone auth (phone number provider) - and gets an sms message.
The SMS should trigger an automatic verification in some cases or he types in the 6 digit code from the sms message
But based on the docs on account-linking, rather than call FirebaseAuth.signInWithXXX here, we can instead call FirebaseUser.linkWithCredential(PhoneAuthCredential).
So i was wondering if a phone number verification is considered complete without an explicit sign-in with the PhoneAuthCredential ?
You can link a PhoneAuthCredential to an existing user, in your case, a user with a GoogleAuthProvider.
After you sign in the user with Google.
You then go through PhoneAuthProvider.getInstance().verifyPhoneNumber(phoneNumber, ...)
This would resolve with a PhoneAuthCredential or a verification ID. You can then ask for the SMS code and instantiate a PhoneAuthCredential via PhoneAuthProvider.getCredential.
You can then link that credential to the currentUser: currentUser.linkWithCredential(phoneAuthCredential)
For future comers and javascript users here is a way to achieve that:
const phoneCreds = firebase.auth.PhoneAuthProvider.credential(this.windowRef.confirmationResult.verificationId, phoneConfirmCode);
firebase.auth().currentUser.linkAndRetrieveDataWithCredential(phoneCreds)
.then(response => {
console.log('*********', response);
// Manage other firestore data
})
.catch((error) => {
console.log('error', error);
});

AWS Cognito: Restrict users to a one login at a time

Is there any way to restrict users to a single [simultaneous] session?
I'd like to be able to check if the current user already has a session. If they do, then they can opt to sign that session out, before continuing.
To be clear, at the moment it is possible to login the same user from multiple browser tabs, (from the same cognito application)
cognitoUser.authenticateUser(authenticationDetails, {
cognitoUser: this.cognitoUser,
onSuccess: (result) => {
this.userSession = result
console.log('successfully logged in', result)
// But are they already logged in somewhere else?
},
onFailure: (error) => {
console.log('Login failed for some reason...')
callback(error)
}
}
I understand that Cognito is built with mobiles/apps in mind so this might not be possible without using a login lambda hook... ? Even then I'm not sure if it's possible without maintaining a table of logged in users...?!
You can signs the current user out globally from all the devices by invalidating all issued tokens
cognitoUser.globalSignOut();
or signs the current user out from the application in existing session in the browser.
if (cognitoUser != null) {
cognitoUser.signOut();
}
You can onvoke either of the above just before user sigins in back again using the login screen.
I used the admin API - "AdminUserGlobalSignOut" for invalidating all the session tokens provided to the user before I send the login request from my lambda to Cognito.
You can refer to this link for official docs from aws.
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUserGlobalSignOut.html
Pro Tip - AdminUserGlobalSignOut endpoint kills the refresh token
validity not the Id Token validity - so if the creds are shared at
12pm and the user signs in using another device in 5 mins or so - the
first device ID token login will still work on the first device until
its not expired - by default ID Token is valid for 1 hour.

How to handle email verification after creating a new account?

When I create a new user in Auth0 (username password authentication) a verification email is sent out to the user.
Without verifying the email the user is still able to sign into Auth0. Actually this is what I want in this particular scenario, however, what is the usual flow in this?
I tried searching for documentation on this verification process on Auth0 but could not find any. Plus if I want the user to verify the mail before signing in how do I configure this? Is this documented somewhere?
As you mentioned, email verification is natively supported in Auth0 when using the username/password authentication. The status of the email verification procedure is tracked through the email_verified property available in the user profile.
By default and inline with what you experienced, authentication is not blocked for non-verified users, however, you can quickly achieve this through a rule (Force email verification):
function (user, context, callback) {
if (!user.email_verified) {
return callback(new UnauthorizedError('Please verify your email before logging in.'));
} else {
return callback(null, user, context);
}
}
As noted in the rule page you can also handle this in the application itself by checking the user profile and conditionally reply based on the email verification flag; this will allow you to provide a more customized experience for non-verified users.

Firebase Auth linking anonymous auth user with custom auth user

So I saw here: https://firebase.google.com/docs/auth/web/account-linking#link-auth-provider-credentials-to-a-user-account That it is now possible to link user accounts in Firebase. I also saw that Firebase provides the functionality of anonymous authentication, where it creates a user session for a user, without any credentials.
In our application we normally use CustomAuthentication with Firebase, as we have our own authentication service. This works perfectly, and we are able to use the same Auth system in-between systems that use Firebase, and the ones that don't.
Now we got to the point where we wanted to take advantage of the anonymous authentication of Firebase, to allow users to use the apps without registering, and just transfer their details after they log in. So I thought that account linking is what I need. But I can't find a way to link an anonymous account with a custom authentication account. Is something like this possible with Firebase?
I have not found linking between anonymous and custom signIns too, so I just use signInAnonymously and pass it's uid to signInWithCustomToken.
Step 1.
To be able acheive this, you should grab an uid from signInAnonymously function like this:
var uid;
auth().signInAnonymously().then(user => {
uid = user.uid;
});
Step 2.
Save current user data like this:
database().ref(`users/${uid}`).set({ some: 'data' });
Step 3.
Send this uid to your server which returns custom token. On your server you just pass this uid to firebase.auth().createCustomToken(uid) function and send this custom token back. It will contain the uid.
Step 4.
When you receive custom token, you can sign in with it like this:
auth().signInWithCustomToken(authKey);
And that's it. You are signed in with your custom token and can access your anonymous user data saved on the step 2.
I had a similar problem but I believe Firebase does not allow this type of linking because it would require linking two separate firebase user ids: the id of the custom token created user and the id of the anonymous user.
Firebase docs say:
Users are identifiable by the same Firebase user ID regardless of the authentication provider they used to sign in.
So handling linking between two user ID's would cause inconsistencies.
I got around this problem by doing a merge of the data between the two accounts.
For example (from Firebase docs):
// Get reference to the currently signed-in user
var prevUser = auth.currentUser;
// Sign in user with another account
auth.signInWithCredential(credential).then(function(user) {
console.log("Sign In Success", user);
var currentUser = user;
// Merge prevUser and currentUser accounts and data
// ...
}, function(error) {
console.log("Sign In Error", error);
});
Caveat: I've never done this. Have you seen this page? Down at the bottom, under the heading "Email-password sign-in", it lists this code fragment:
var credential = firebase.auth.EmailPasswordAuthProvider.credential(email, password);
You can then (apparently) link the credential like this:
auth.currentUser.link(credential).then(function(user) {
console.log("Anonymous account successfully upgraded", user);
}, function(error) {
console.log("Error upgrading anonymous account", error);
});

How to implement password protect security in JsonStore Worklight 6.2?

I want to implement the app in worklight using JsonStore protection i want to store password based on logined user and add those password to options in WL.JSONStore.init(collections,options). The rest of the details in data object data={};
and how do i extract the password saved WL.JSONStore.init(collections,options) options object for making api calls for rest of the functions?
My take on the question:
Storing the password in the device is indeed not a good practice to follow.
There is also the additional question of where the username and password are coming from originally? When does the sign-up (rather than log-in) happens? This is IMO crucial information.
In one of my applications I have initialized a JSONStore and encrypted it using the user's password and in the collection I saved the username.
This way, the next time the user tries to open the JSONStore (read: "to log-in"), it will try to do so with the inputted password. If this step is successful, it will then compare the inputted username with the stored username. If this step is successful as well, valid login credentials can be assumed.
var collections = {
userCredentials : {
searchFields : {
username: 'string'
}
}
};
var username, password;
username = $("#username").val();
password = $"("#password").val();
WL.JSONStore.init(collections, {password:password})
// first step is successful
.then(function() {
return WL.JSONStore.get("myCollectionName").find({username:username});
})
// second step is successful
.then(function(searchResult) {
if (searchResult[0].json.username == username) {
// valid login.
}
})
.fail(function() {
alert ("Invalid credentials, try again.);
})
Note that the above code is a bit abstract and "generic", and you will need to handle all sort of edge cases.
I highly recommend to thoroughly read all of the JSONStore documentation and training modules.
You have two options (though I am not a security expert):
Ask to user that uses the app (and therefore the JSONStore) to enter the password each time you open the app and then in the WL.JSONStore.init method check the password (if the password is correct, the store will open, otherwise, the method will fail).
Store the password in a secure storage - Keychains. For iOS see this link. For Android, I think this is the equivalent link.
So, the first time the user opens the app, you store the password and each time the user opens the app, you retrieve the password and pass it to WL JSONStore. If the user wants to update the password (e.g. you have security policy to follow), you have to update the password in the Keychain.
Of course, if you go hybrid, you will need some sort of Cordova plugin that add, reads, updates, resets the password in the keychain so you can make these actions from JavaScript.
Hope it helps!