Disallow user login if email_verified is false - amazon-web-services

When a user registers for my application I handle the request through an API and send an email containing a verification link. When the link is clicked it updates the email_verified attribute to true. This is working as expected.
The problem I'm having is that a user is allowed to login even when the attribute email_verified is set to false.
I'm using amplify to login the user. How can I block user login if the email has not been verified?

I found out the answer to this myself. I was registering the user with a custom lambda function which creates the user using adminCreateUser. This API automatically sets the UserStatus to CONFIRMED which is the field that is used to determine whether a user can log in or not. I was working on the assumption that it was the email_verified field which determined this, which was incorrect.
I fixed this by instead using the signUp function of the API which instead creates the user in an UNCONFIRMED state and doesn't allow login until the sign up is confirmed.

Related

AWS Cognito - PostSignUp Trigger Not Working

i have a post signup trigger setup to store the user details in DynamoDb table. This works fine when the user signs up on their own through the front-end but the trigger is never invoked if the user is created through AdminCreateUser API. Our assumption was after the newly added user gets an email with a temporary password and logins through the front-end, Cognito will invoke the postsignup trigger.
Is that an expected behavior? And also, how do we address this issue?
Although that's counter intuitive, seems that's the expected behavior.
Post Confirmation trigger is not invoked when a user is created via AdminCreateUser API.
Workaround could be to to use Post Authentication trigger and during processing of the fired event to check if cognito:user_status is FORCE_CHANGE_PASSWORD.
When a user is created using AdminCreateUser, status of the new user is set to FORCE_CHANGE_PASSWORD. Once user logs in and changes temporary password, status is changed to CONFIRMED.
Downside is that trigger is invoked after every login.

Unable to confirm the user registration via AWS SDK

The AWS documentation for JS SDK says:
Force Change Password
The user account is confirmed and the user can sign in using a temporary password, but on first sign-in, the user must change his or her password to a new value before doing anything else.
User accounts that are created by an administrator or developer start in this state.
But if for such a user I try to call forgotPassword method of SDK, it errors saying something like: Password cannot be reset in the current state.
SO how can I complete the registration of a user (created by admin in IAM) from my website. Which is the SDK method that should be called ?
Setting up an Auto Verify Lambda Trigger on the Pre Sign Up Trigger will allow for the user to be a confirmed state, which may get you to the point you are looking for?
Lambda -> Node.js
Give it an appropriate Title
Place the below value in the code:
exports.handler = (event, context, callback) => {
// Confirm the user
event.response.autoConfirmUser = true;
// Set the email as verified if it is in the request
if (event.request.userAttributes.hasOwnProperty("email")) {
event.response.autoVerifyEmail = true;
}
// Return to Amazon Cognito
callback(null, event);
};
Save
Then Select newly created trigger in General Settings -> Triggers -> Pre sign-up
We can do this,
I previously answered mongodb to aws cogniton migration question.
Go through step by step. I explained that the user's created by admin need to change the password(forgot password) but there's still another way to do it. Checkout my answer,
Some content from my answer,
AdminCreateUser:
Create a new user profile by using the AWS Management Console or by calling the AdminCreateUser API. Specify the temporary password or allow Amazon Cognito to automatically generate one.
Specify whether provided email addresses and phone numbers are marked as verified for new users. Specify custom SMS and email invitation messages for new users via the AWS Management Console.
Specify whether invitation messages are sent via SMS, email, or both.
After successful user creation,
authenticate user using same user credentials Use: SDK calls InitiateAuth(Username, USER_SRP_AUTH)
After success of initateAuth, amazon Cognito returns the PASSWORD_VERIFIER challenge with Salt & Secret block.
Use RespondToAuthChallenge(Username, , PASSWORD_VERIFIER)
Amazon Cognito returns the NEW_PASSWORD_REQUIRED challenge along with the current and required attributes.
The user is prompted and enters a new password and any missing values for required attributes.
Call RespondToAuthChallenge(Username, , ).
After successful password change user can be able to login using same credentials which admin created.
Refer: Unable to confirm the user registration via aws

AWS Cognito - How to determine if a user signed up with email or phone number

We have implemented the Custom Auth Triggers as described here. We have the user pool set up to let users login with either phone number or email.
The problem I am having is determining what medium (email or phonenumber) the user signed in as. I am using CognitoIdentityServiceProvider#signUp to reg / login a user.
When observing the event passed into the define / create / verify auth triggers, it seems like doesn't pass through what the username was used to initiate the authentication flow.. only the user attributes which in my case there could be both email or phone. I need to know which one it is so I know if i need to send the code through SMS or Email.
I have tried to add a custom UserAttribute with a prefix of custom: so I could do something like custom:preferredAuthMedium but that doesn't seem to populate the UserAttributes map on the user even though the docs say it should.
Is there a standard way to do this with the custom authentation flow?
This is a workaround by adding a custom attribute during passwordless login
Actually, the authenticationUser function needs to identify whether the user is adding email or phone during login
Step 1: during login process, before calling initiateAuthCommand, First set a custom attribute in Cognito user object - logged_in_by - email or phone
Step 2: once you add a key after that InitiateAuthCommand will be started and call the triggers
Step 3: When createAuthChallenge runs at the time we will have userAttributes.logged_in_by
If this attribute contains email this indicates that the user is trying to login with the email and we need to send OTP over email.
If this attribute contains a phone this indicates that the user is trying to log in with the phone and we need to send OTP over the phone number.
Different medium requires their own confirmation.
The following attributes says which medium the user signed up or verified for,
phone_number_verified is phone number.
email_verified is for email.
Hope it helps.

AWS Cognito - run another lambda after migration lambda has run

Cognito has a migration lambda that allows us to confirm a user in our db. They send the email and PW to Cognito, the lambda fires, we verify matches, and the user is entered into Cognito.
At this point - behind the scenes - Cognito generates a username of some kind (UUID). The problem is, I need a way to get this username into our existing database, because our systems going forward will no longer rely on email and instead rely on this username.
Ideal flow:
Sign In
Migration Succeeds
Cognito generates username
Username is sent to our server.
Now because we have email set to auto-verified, no post-confirmation lambda can be called. The only way I see to do this with Cognito as-is is to either:
Ask users who already exist in our system to confirm their email again. This is a non-starter
Create a post-auth lambda, check user login count through a custom attribute, and if 0 (or if not already registered with the service, etc.) migrate the username to the new service.
If there is any other way to do this, please let me know.
After the user migration lambda is called your pre sign-up lambda will be called, assuming you have implemented it. The parameters received by your lambda will include username with the value being the UID you referenced. Parameters will also include user attributes containing email. You can use this information to update your database.
I did not want to add the PreSignup trigger, its a complicated way of doing it if you already rely on PostConfirmation, and if the majority of new users won't be migrations. My use case has a frontend initiate the signup process as well, which I use here.
Instead, I set a Cognito attribute on the new user during the UserMigration trigger. It could be 'user_migration': <oldUserSub>, or however you want to mark it. Just make sure you allow this property within the Cognito user pool settings.
When the UserMigration trigger returns, this information is now accessible through verifying the IdToken, or found in the JWT on the frontend if you're using that. So, when the user is migrated into Cognito and the response gets back to the Cognito client on the frontend, I can now recognize this user needs to be migrated into my personal database. Seeing this, I'll call a new endpoint on my backend to handle this. This new endpoint does exactly what PostConfirmation would typically do.
Then just delete the 'user_migration' property from the Cognito user, return the new user data to the frontend and everything should be set up.
You can use Pre sign-up trigger. In order to detect if the trigger event came from your migration trigger, you can check at the trigger_source value from the event object. In my case (i'm using migration trigger) the value is PreSignUp_AdminCreateUser. By knowing the value of trigger_source you can differentiate if it was migrated or regular user. You can also check the user attributes to know whether the email or phone is verified or not.
Here's my sample code on python:
def lambda_handler(event, context):
trigger_source = event.get('triggerSource')
user_attributes = request.get('userAttributes')
email_verified = user_attributes.get('email_verified')
if trigger_source == 'PreSignUp_AdminCreateUser' and email_verified == 'true':
# create user on db

Check for expired account for users created by adminCreateUser in AWS Cognito

I have a Lambda function which creates users using adminCreateUser Cognito function. My app is basically an invite only app where the admin can only invite certain users. Everything is working great so far, and I am able to resend invitation email notifications as well. However, I am trying to figure out how I can find out if a user created by adminCreateUser method has "expired" i.e. the user has not accepted the invite and changed the temporary password.
When the admin creates a user using adminCreateUser the status is FORCE_CHANGE_PASSWORD by default. When the user with this status attempts to Log in using the temporary password (from the verification email), Cognito sends a challenge back in the challengeName attribute of NEW_PASSWORD_REQUIRED, based on which the user is forced to change their password through the application and upon successful reset the status would change to CONFIRMED in Cognito for that user. This is working great so far, but I also need to handle scenario where the invited user never really changed their password by attempting to log into the application.
Now, I have set the - "How quickly should user accounts created by administrators expire if not used?" - to 7 days (default). What would be the status of the user account after 7 days if the user doesn't reset their password? I tried to find out from the documentation but it's not clear what the status of the user account would be in this situation.
NOTE: This is not about Token expiration in the client but rather expiration of an account created via the adminCreateUser method.
Annjawn,
According below link: "After the account expires, the user cannot log in to the account until the administrator updates the user's profile by updating an attribute or by resending the password to the user"
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-admin-create-user-policy.html
All tthe best,
Guto