cognito autoConfirmUser and autoVerifyEmail - amazon-web-services

I have cognito set up with a pre sign up lambda which returns event with following set:
event.response.autoConfirmUser = true;
event.response.autoVerifyEmail = true;
this correctly marks user email and user itself as confirmed in aws console. But while trying to login I get the error "User does not exist." from cognito aws api, any ideas?
Cognito Pool is set up to use "email address" as "username" and this makes following even weirder - I can create new user with the same email address as above and authenticate fine. But what I ending up with are two confirmed users with the same email address!
My use case is relatively simple - I invite users to join via email so the email is confirmed already in a sense, that's why am using pre sign up lambda to mark user and email as confirmed/verified.
Any help greatly appreciated!
Thanks,
Tomek

Related

Customizing OTP Authentication flow with AWS Amplify

I've currently integrated an OTP authentication signin flow to a React Native app with Amplify. The flow is as follows.
(I followed the guide provided in this article)
But right now I'm in the need of providing the option of sending the OTP code to a user entered email address in case if it is not received to the mobile number.
Initial thought was to trigger the create auth challenge lambda function via Amplify Auth.signUp by sending email attribute.
import Auth from '#aws-amplify/auth';
const sendVerificationToEmail = async (phone: number, email: string, password: string) => {
await Auth.signUp({
username: phone,
password,
attributes: {
email
} });
}
Then the lambda function can be remodified as follows to either send an email or SMS,
...
const email = event.request.userAttributes.email;
if (email) {
// Logic to send OTP verification code via SES
} else {
// Logic to send OTP via SNS
}
but this is not possible since we already have a user created in the cognito user pool. This attribute will not be passed to the lambda function.
What is the correct approach of achieving this ?
Easiest approach is, Setup lambda function for custom flow.
Create custom method to generate an OTP and save it to into a table and
then use SES to send OTP to email .
Create custom method to verify OTP.
Check OTP from table and verify it.
if(SUCCESS)
use admin to mark as verified
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminConfirmSignUp.html

AWS Cognito - how to confirm user after signing up?

I am trying to build an app in React Native with AWS Cognito as authenication pool. My user pool is set to use MFA(optional). My app has both phone/OTP based signup/sign and Social logins. When I signup with a phone number, I get the OTP and all my triggers are working.
Problem is when I signup with a email, I don't get the user signed session or Auth.currentAuthenticatedUser() always returns Not authenticated
My code
const cognitoUser = await Auth.signUp({
username: user.email //I get the email from Google signin SDK
password: Date.now().toString() // some random password
});
const signedInUser = await.signin(user.email) //This returns user info, but signinSession is null
I saw people saying the user record must be confirmed, so I tried both of these and both didn't seem to be working
Auth.sendCustomChallengeAnswer(
cognitoUser,
1111 // Some random number as my Lambda trigger will be sending OTPs to phone numbers only
);
Auth.confirmSignUp(
cognitoUser,
1111
)
I also noticed the authenticationFlowType is USER_SRP_AUTH in this case, I was expecting it to be CUSTOM_AUTH
Right now I am stuck with this, not able to get the logged in user info in subsequent app screens.Any help will be appreciated.
If you already have it set up such that the sign up email address used in Auth.signUp will receive a verification code, then you will be using Auth.confirmSignUp.
However note the method signature from the type definition file:
confirmSignUp(username: string, code: string, options?: ConfirmSignUpOptions)
The verification code is a string; not a number as you had posted.

What is "cognitoUser.getAttributeVerificationCode"?

I'm convinced that Amazon goes out of its way to make understanding their platform as difficult as is possible.
I've read over the documentation regarding "cognitoUser.getAttributeVerificationCode" at Amazon only to have it make me even more confused!
Verify an Attribute
The following example verifies user attributes for an authenticated user.
cognitoUser.getAttributeVerificationCode('email', {
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
},
inputVerificationCode: function() {
var verificationCode = prompt('Please input verification code: ' ,'');
cognitoUser.verifyAttribute('email', verificationCode, this);
}
});
Can anyone help me understand what this is (cognitoUser.getAttributeVerificationCode) and/or how I would use it? I don't understand why I would verify an email attribute w/a verification code.
The verification code is sent to the users email. The user has to properly receive that email to retrieve the code and enter it in a UI so that the email is set to verified in Cognito. That user can then reset their password using that email.
What if the user had entered an incorrect email? Or their email system didn't allow them to receive the code sent by AWS?
By sending out a verification code, and having the user send it back, Cognito verifies that the email was entered correctly and belongs to that user. This can seem like a pain but is standard on many web platforms now days...The same process is needed with phone numbers for users in your Cognito user pool.

How to disable a user's password in AWS using boto3

I am auditing user passwords in AWS using boto3 and I'm not finding a way to accomplish the following CIS Benchmark: "Ensure credentials (with password enabled) unused for 90 days or greater are disabled."
I have the code to pull the password age and to pull the last time the password was used, but I do not find anything to make inactive a password.
For access keys (but not passwords), we have the following:
client = session.client('iam')
... (get user and keyid) ...
last_used = client.get_access_key_last_used(AccessKeyId=keyid)
... (determine the age of the key) ...
if age >= 90:
client.update_access_key(AccessKeyId=keyid, Status='Inactive', UserName=user)
Does anyone have any pointers?
delete_login_profile is the one you should use if you want to delete the password for the specified IAM user, which terminates the user's ability to access AWS services through the AWS Management Console.
However to prevent all user access (including CLI and API access) you must also either make any access keys inactive or delete them.
From Boto3 Documentation:
Warning
Deleting a user's password does not prevent a user from accessing AWS
through the command line interface or the API. To prevent all user
access you must also either make any access keys inactive or delete
them. For more information about making keys inactive or deleting
them, see UpdateAccessKey and DeleteAccessKey.
If you want to change the password, you should use update_login_profile boto3 API. If you want to disable the password, you need to use delete_login_profile.
boto3 documentation for update_login_profile can be found here.
boto3 documentation for delete_login_profile can be found here.
Thanks to the responders, delete_login_profile followed by a password reset using create_login_profile is exactly what I needed. I saw it in the docs, but "delete" just sounded too scary.
def getPassword(client, user):
''' get the password data from aws '''
try:
response = client.get_login_profile(UserName=user)
return response
except client.exceptions.NoSuchEntityException as e:
print(e)
return ''
# setup the client handler
client = session.client('iam')
# set the user
user = 'some.user'
# if the user has a password, execute this code block
if getPassword(client=client, user=user):
... code to test the password age here ...
... if it's too old, then ...
# remove the login_profile/password/ability to use the Console
client.delete_login_profile(UserName=user)
# set the new password
passwd = raw_input('Enter New Password: ')
# create the new login_profile with the new password and force the user to change the password on the next login
client.create_login_profile(UserName=user, Password=passwd, PasswordResetRequired=True)

AWS Cognito username/email login is case-sensitive

Setup
I am using AWS Cognito to manage the user registration and user access for my web application. Specifically I am using the Cognito hosted UI. This means that Cognito presents a UI for my users to register, I do not have access to modify the user sign-up or login pages for my application (other than the controls provided by Cognito). I am using email addresses as usernames, so new users are simply asked to provide an email address and password.
Problem
Cognito treats email addresses as case sensitive. If a user signs up with the email address JOHN_smith#randommail.com, they cannot then sign in using john_smith#randommail.com.
I want user email addresses for sign-up and login to be case insensitive.
What I have tried
Usually this would be trivial to deal with by setting the email address to the lowercase in the client before sending it to the server. However I do not have access to the client UI as it is hosted by Cognito.
My plan therefore was to try using a Lambda function invoked by a Cognito pre-signup trigger to lowercase the email supplied by the user.
Pre sign-up
Amazon Cognito invokes this trigger when a user attempts
to register (sign up), allowing you to perform custom validation to
accept or deny the registration request.
Here is the lamdba function I wrote:
'use strict';
console.log('Loading function');
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
var triggerSource = event.triggerSource;
console.log('Received triggerSource:', triggerSource);
var email = event.request.userAttributes.email;
console.log('Received email:', email);
var modifiedEvent = event;
if (email !== null) {
var lowerEmail = email.toLowerCase();
modifiedEvent.request.userAttributes.email = lowerEmail;
console.log('Set email in request to', lowerEmail);
console.log('Modified event:', JSON.stringify(modifiedEvent, null, 2));
} else {
console.log('Email evaluated as NULL, exiting with no action');
}
// Return result to Cognito
callback(null, modifiedEvent);
};
This 'worked' in the sense that the email address in the event request was modified to be lowercase (john_smith#randommail.com). However, it seems the account has already been created in the userpool by the time my Lambda function receives this event. Changing the email address in the request had no effect - the original email address (JOHN_smith#randommail.com) still appears in my user pool. I suspect the only fields in the event that have any effect are the response fields. Here is what my modified event looks like:
{
"version": "1",
"region": "us-east-1",
"userPoolId": "us-east-1_xxxxxxx",
"userName": "xxxxxx-xxxx-xxxx-xxxx-xxxxxxx",
"callerContext": {
"awsSdkVersion": "aws-sdk-java-console",
"clientId": "xxxxxxxxxxxxxxxxxxxxxx"
},
"triggerSource": "PreSignUp_SignUp",
"request": {
"userAttributes": {
"email": "john_smith#randommail.com"
},
"validationData": null
},
"response": {
"autoConfirmUser": false,
"autoVerifyEmail": false,
"autoVerifyPhone": false
}
}
My question
I'm looking for ideas or examples to make my user registration and login case insensitive. This might include changes to my lambda trigger approach or something else entirely.
Please note I know I could implement my own UI, which I will only do as a last resort.
Fixed on new user pools. You can turn off case sensitivity now.
https://aws.amazon.com/about-aws/whats-new/2020/02/amazon-cognito-user-pools-service-now-supports-case-insensitivity-for-user-aliases/
You could trigger a Lambda function after sign-up to change the email to lowercase. Without actually testing it, you should be able to trigger a Lambda post confirmation. That Lambda could use AdminUpdateUserAttributes API, called from your SDK of choice, to change the email to lowercase.
Note that user names are also case sensitive.
Since username is case sensetive: why not just use the username as the email address and have the prehook populate the email field with the username?
Make username lowercase when creating the account. Make username lowercase when logging in. At least this way you only have to re-create users that have uppercase characters. Or you can rebuild your entire user pool and migrate the users, but who knows what affect that will have on passwords and MFA. It doesn't seem worth the trouble with an existing user pool. Hopefully you are doing a brand new project and you can select the case insensitive option when creating the user pool.
After multiple attempts, I have tried adding a small css for username field on login page and forgot password page.
#amplify-id-8,#amplify-id-0{
text-transform: lowercase;
}
#amplify-id-0::placeholder,#amplify-id-8::placeholder{
text-transform: capitalize;
}
This worked for me on the amplify-authenticator , I used as a login component.
another possibility is if you can create a user signup api, which would create the user in the cognito. after trimming email along with performing lower case on email. you can perform your custom steps before that.
you are right that pre-signup trigger basically get invoked after signup is performed.
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html#aws-lambda-triggers-pre-registration-tutorials