AWS Cognito Workflow: Using email alias for primary username - amazon-web-services

So I am trying to get my head around AWS Cognito but I have hit some walls.
So, right now I can register an account, and verify it and sign in. Simple enough. The edge cases are where my walls are.
Here's the info I have so far:
username's cannot be changed once created
I am using UUIDs as my username values
email is marked as an alias, which in Cognito terms means I can use it to sign in with in addition to username.
if email is chosen as an alias, per the docs, the same value cannot be used as the username (http://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases):
If email is selected as an alias, a username cannot match a valid email format. Similarly, if phone number is selected as an alias, a username that matches a valid phone number pattern will not be accepted by the service for that user pool.
The email address can ONLY be used to sign in once the account has been verified (http://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases)
Phone numbers and email addresses only become active aliases for a user after the phone numbers and email addresses have been verified. We therefore recommend that you choose automatic verification of email addresses and phone numbers if you choose to use them as aliases.
Here in lies my edge case.
If a user signs up, but does NOT immediately verify:
they get called away
maybe the app crashes
they lose connectivity
their battery dies
they force quit
app get's accidentally deleted.
In their mind they have signed up just not verified their account. At this point it effectively leaves no way to verify their account they thought they signed up for. I guess it could be solved with messaging:
"Warning your account will not be created until you verify your email address." or something along those lines. Anyway...
They can't attempt to sign in as they won't know the UUID that was randomly assigned as their username.
Even if that wasn't the case, they provided their email address as their username. From the user's POV they would have no idea what their username could even be since they only entered their email address.
The best they could hope for is to try to sign up again. (Assuming they read the verification warning above) In this case now Cognito potentially has abandoned unconfirmed accounts piling up.
"Piling up" may be too strong a phrase, this is likely a pretty fringe case.
Now the plus side is, since they have not "verified" their email they can sign up again with the same email address since the email doesn't get uniquely constrained until it's verified. If someone tries to verify an address that has already been verified they get a AliasExistsException. This actually brings up an interesting point which I just tested as well.
I can register with an email address, then verify that email address so the account becomes confirmed. I can then turn right around and sign up with the same email address and I don't get an official AWS error until I try go to verify that account with the duplicate email address. There isn't any way to surface this error earlier? I guess the expectation is that it's on the developer to write a verification service in the Pre-Signup Trigger:
This trigger is invoked when a user submits their information to sign up, allowing you to perform custom validation to accept or deny the sign up request.
To sum up, and to restate the question:
It seems to be required, practically speaking, that when using an email address with Cognito a Pre-Signup Lambda is required to ensure an account with an email doesn't already exist since the AWS Exception won't be handled until a verification attempt is made.
Is my assumption here correct? By required here I think it's pretty reasonable to let a user know an email address is not available as soon as possible. For example:
John Doe : jdoe#gmail.com
Jane Doe : jdoe#gmail.com

You are correct.
Another solution is to create a lambda (not triggered by preSignUp) and called whenever the user finished typing into the email field. And getting a response "This email is already used" or "This email is available" before even sending the sign-up event.
Referring the first part of your question. If the user does not immediately verify their email. You probably mean confirmation by code. I prefer using confirmation by link sent to email which avoids this problem.

Knowing that this is an old question, here's a solution for posterity... I am using generated UUIDs for usernames, just like you, undisclosed to the user.
When the user wants to confirm the code at a later time (or perhaps ask to resend it), he doesn't know the username but he does know the email address that he registered with...
You can search for Cognito users with a certain email (or any other attribute) using ListUsers with a filter like email = "user#signupemail.com".
Once you find the user, you can access their username via response.Users[0].Username, and use it to confirm the account.

Related

AWS Cognito: How can I prevent multiple registrations with the same email address?

In my user pool, I currently see two options for the login flow:
Using username and email adress
Using email adress or phone number
Option 1: The username is unique. You will get an error message if you try to register again with this username. BUT: The email address is not unique. You can try to register again with this email address. The user will then be created in the User Pool, but you will not be able to reconfirm this email address.
Option 2: The email address and / or phone number are unique. But the username can no longer be used to log in.
What do I want?
I need a mix of both options. I want my users to log in with username AND email address (which is the case with option 1), but I don't want to allow them to create multiple accounts with the same email address (they need a unique email as with option 2).
Is there an easy way to accomplish this? I couldn't find anything in the Cognito Console and feel like I need something like a custom Lambda trigger .... Thanks for any tips!
Your are already going into the right direction. You need a pre-signup lambda to do the check of email uniqueness for you. Should be relatively straightforward Here is the link to the documentation about how to set up such lambda:
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html
Your Lambda needs to be able to execute actions on the User Pool to figure out if user with a specific email already exists.
The easiest way to search for such users is to use the ListUsers API (https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListUsers.html) with a filter to select only users having the email address in question.

AWS Cognito userpool changed email address pointless validation code?

i have set up a user pool using option 2 ( see docs here ) where i use the email address to sign in together with a password.
users are able to register and log in successfully.
users can successfully change the email address.
i then use this code to change the email address:
cognitoUser.updateAttributes(attributeList, function (err,
result) {....}
the confusion or problem is:
changing the email address automatically sends a validation code to the new email address. what do i need to do with this code as the email address is changed without validation and the user can use the new address to login without any problems.
is it necessary to validate the changed email address when the address seems to be automatically validated without using the validation code? if i don't have to use the validation code, is there any way of preventing it being sent to the user when they change the email address as they will probably be confused when they receive it seeing that the changed email address works?
thanks
Verification is needed when user will try to use forgot password. If email is not verified the code for reseting password will not be send.
You can prevent it from being sent from General settings > MFA and verifications under "Which attributes do you want to verify?"

AWS Cognito User Pool - how to keep phone numbers unique while phone number is not a login alias

I'm using AWS Cognito User Pool on public website.
Phone number is not login alias as a result of business/security requirement.
I have a requirement for users to have unique verified phone numbers.
I have to verify both email and phone.
However, because of #2 Cognito allows several users to have the same verified phone number, thus I'm struggling with #3.
I've tried to use Post-Confirmation lambda, but if phone is already confirmed, lambda doesn't get triggered on email confirmation, since Cognito considers that a user is already confirmed after phone or email are confirmed - this already kills that idea, but I also suppose that even if I throw exception, user will remain confirmed.
Additional complexity is being added with ability of users to change their phone/email anytime out of our website (since due to publicity there is no client secret).
It would be ideal for me, if Cognito would have a lambda event for pre-confirmation of phone and email. But what can be a workaround here?
The behavior you describe is correct. Unfortunately, if you don't use phone number as alias in your user pool you can have the same number in the verified state in multiple accounts. That requirement (a single verified phone number in a user pool) is only enforced if phone number is an alias.
I will mention the use case and your lambda trigger suggestion within the team as a feature request.

How to design email and username login

I have two question about usernames and emails
1. I judge username is a Email if '#' in username, and auth it follow:
email_user = User.objects.get(email__iexact=username)
authenticate(username=email_user.username)
Is that a good way that you recommended? or you may have a better advice?
I know a AbstractBaseUser can do it, but I think use User is more reasonable.
2. Should I store the user's email within the User.email field?
Imagine if I sign up a new user with:
username: '123'
email: '456#google.com'
and when I signup success, then I find that my email is wrong,
and now another user that email is '456#google.com' can't signup again.
I just want to a email is verified that can associate with the user.
what's your advice?
If you want to use email as your unique sign in key, it would save you a lot of trouble in future development of your website if you make a custom User model using AbstractBaseUser. If you want i can post a sample working code
In reference to your second question - You can use Cryptographic signing in Django (https://docs.djangoproject.com/ja/1.9/topics/signing/) to produce a key. Further send this key as a link (eg www.example.com/verify/:some_crypto_key:) and send it as a link to user's email address. This key will contain user id and time stamp. If you receive a request on that link, it means that email is legit. You may find a package that does a similar task maybe.
EDIT:
Implementation (short way) - As the user signups on your website, Immediately ask him/her to verify account using the link you have sent to the given email. If you do not receive a response from that email within a given time (say 20 mins), delete that user entry. This means that you can not let the user access your website until he/she verifies the account.
Flaw - Consider a situation where the user has submitted a wrong email. It is obvious that the user will never be able to verify it but for those 20 mins if co-incidentally the actual user with that same email tries to signup on your website, he won't be able to access. This is very unlikely. Also this user will receive an email from your website saying that user has signed-up on a website (so here you can provide another link, 'if this was not you, please click here' kind of thing)
Unless you have a burning desire to write your own custom user model, which will let you replace the username field with the email, I would recommend using something like Django AllAuth. It includes email verification (as outlined in your question), and can be set to use email as username fairly easily. It's a well established library with lots of support, and will be more immediately usable than rolling your own.
(That said - rolling your own is an illuminating experience, and RA123's point is the answer you should accept if you're going down that road.)

Facebook Login and email verification

Has Facebook always verified the email addresses for their users?
I am building an app with Django (using python-social-auth) where I want people to be able to login with their Facebook account. As far as I understand, the email is always verified. Even in the case when the person who has signed up used his/her phone number. If they enter an email later on, this email will still be verified.
However, I am not sure this was the case earlier. Can we trust that all the emails have been verified by Facebook for all the accounts?
More recently, the short answer is: Yes, if you get email from Facebook, this is verified email.
Also, remember that users may not have it set (i.e. phone registration) and probably, if you want to handle them, you will need to extend your pipeline to verification.
(But that allows you to handle for example twitter)
Anyway, more info in twin topic: Is it possible to check if an email is confirmed on Facebook?
In case anyone finds this question again, as of 2021, Facebook's documentation says that the email obtained from Facebook needs to be verified.
"1. Ensure the Facebook Login email address is verified
If you use an email address as the unique credential which identifies each account, your app should verify that the email address associated with the person's Facebook account (and obtained during Facebook Login) is valid. You can do this by creating code in your app to send a verification email to the address obtained after Facebook Login."
Source: https://developers.facebook.com/docs/facebook-login/multiple-providers#postfb1