How do I get an UNCONFIRMED account's AWSCognitoIdentityUser object? - iphone

In the AWSCognitoIdentityProvider iOS Swift library, to resend a verification code either by SMS or email, a user object is required and this is retrieved from calling a user pool's SignUp method. Once the SignUp method is successfully called, a user object, of type AWSCognitoIdentityUser, is returned. To resend a new verification code one of the following two methods can be called on that user object:
var pool: AWSCognitoIdentityUserPool?
override func viewDidLoad() {
super.viewDidLoad()
self.pool = AWSCognitoIdentityUserPool.init(forKey:
AWSCognitoUserPoolsSignInProviderKey)
}
...
AWSCognitoIdentityUser.getAttributeVerificationCode("email")
// or
AWSCognitoIdentityUser.resendConfirmationCode()
However, after 24 hours, if a verification code isn't used to set an account in the "CONFIRMED" state, the verification code expires by default, and a new one is required for verification. If the user closes the iPhone app, there is no way I can find to retrieve the user's AWSCognitoIdentityUser object in order to resend another verification code to them. The user can't login to retrieve the user's object because UNCONFIRMED accounts can't sign in. Attempting to re-SignUp using the SignUp method fails because the account already exists.
How do I get an UNCONFIRMED account AWSCognitoIdentityUser object in order to resend a new verification code?

This issue has been open since May 23, 2016, and appears to still be open. See this exact issue discussed at aws/amazon-cognito-identity-js Issue #42 on github.
According to the issue discussion, above, a workaround may be not to use email aliases in the Cognito user pool, but instead require a username to avoid the alias issue which causes the wrong exception (user not found) to be returned and thus no signal that the account exists and is in the UNCONFIRMED state. I'm still not sure if this will enable a method to return the user account's AWSCognitoIdentityUser object used to resend a new verification code, but I will try this workaround and report back.
EDIT:
Found that you can use getSession for a specific user account. It's undocumented that it takes a password. You can use "deadbeef" as the password and it still gets that user's object. Once retrieved, a new verification code can be sent, even if the user is unconfirmed. Recomend doing this before calling sign-up to check to see if the user exists, if it's authorized to pull the user, if resources are available, if the user is unconfirmed (I automatically send another verification if this is the case because I use e-mail verification links), etc.

Related

AWS amplify (cognito) - change phone number during signup and verification

I have the "happy path" of signing up a user implemented using Flutter & AWS Amplify. I have made the user to verify their account using their phone numbers so that the verification code is sent to the phone and the signup process is completed.
I realised that, during testing, one could easily make a mistake. So I want the user to be able to go back and change the phone number so that the verification code is sent to the correct one. However, using Amplify, you cannot change the details if the user is not signed in, and the user cannot be signed in unless their account is "confirmed". Of course, their account cannot be "confirmed" if they don't receive the verification code and with the wrong phone number due to their mistake, they will never receive the verification code...
Has anyone faced the same problem and could help me how to solve this please?
I read that you could use Lambda functions to "auto-confirm" the account without any verification which means they can sign in, which would allow me to change their phone number if they have entered a wrong phone number. But I am not sure if this is the easiest way to do it

Firebase: Standard User Registration/Activation Workflow

I need to implement a standard user registration/activation workflow with Firebase. There doesn't seem to be an obvious way to implement this. When I say "standard", I mean how most email/password accounts work - not necessarily specific to Firebase. I'm sure you're familiar with this. This is the workflow:
User enters their username/password on a form with some validation and submits details
The back-end creates the user record in the database, but the account remains deactivated (i.e. user cannot authenticate - the activated flag is set to false)
The back-end sends an email to the user with a link to activate the account
The user clicks the link in their email which triggers activation. This is probably a Web API of some description.
At this point, the user record's activated flag ticks over to true, and the user can now authenticate
The link probably also has a deep link that opens the app or navigates to a web page
The user can now log into the app
How do I configure Firebase to do all this?
Currently, the app allows the user to register. I am using the Flutterfire SDK. I call createUserWithEmailAndPassword, which successfully creates the user in Firebase. But, the user is already activated. The user should have a state of "disabled" in firebase until the account becomes activated. I can't find any settings to default the user to disabled when the account is first created.
I also managed to get Firebase to send out an activation email by calling sendSignInLinkToEmail, but this call is really designed for email authentication - not email activation. Opening the link should activate the account, but I have not figured out how to do this. This documentation makes it sound like it is possible. Perhaps, the Flutterfire SDK is missing this? I don't want to allow people to log in without a password. I only want to use this call to send out an email.
What am I missing here? Is this non-standard behavior for Firebase? If so, why? If the user is allowed to use an app with an email address that is not activated, they can impersonate someone else. We need to confirm at least that they are custodians of the email address that they are claiming to have.
Do other Firebase people just not worry about this?
Lastly, I know I can achieve this by creating a collection for users in Firebase and putting an "activated" flag there. But, if I do that, I've got to write a cloud function that accepts the link and then updates the user in the collection based on the received link. But I thought this would be automatic in Firebase. If Firebase doesn't have this built-in, I have to put all the security over the top to stop users from authenticating when they have not yet activated their account.
This is a pretty valid concern. I suppose the way around this is to check whether the signed-in user is verified whenever the app is launched. The User object that is returned from Firebase Auth has an emailVerified flag. Check this page for more details.
Using this flag you can choose to show a different screen or pop-up that has a button to send a verification link to the registered email address. Until the user verifies this address, you can limit access to some of the app's screens if you want.
Please note that I have not checked if this emailVerified flag is true for sign ups using Federated login providers like Google Sign-in and Apple Sign In. You might want to check that out.

Dialogflow getting username from Gmail account in inline editor

I have a Dialogflow inline, where when welcome intent is executed I need to call agent.add() so it replies with something like
Hello (username)!
This username is not that the user writes but it's the profile name that he has logged in to the device
In order to get the user's name, you need to request permission from the user. So it usually isn't available as part of the welcoming Intent (at least not the first time they talk to your Action). You need to do one of two things:
Request user information which includes the user name. Once you have requested this information, you can save it so you'll get it the next time the user connects.
Ask the user to sign in. Once they have done so, you'll get an identity token with each request that includes the user's information

Docusign Email authentication

I am using DocuSign for sending email to client/end user by using createEnvelope API of DocuSign. if the end user forwards the email to someone else he /she can view the document and sign on his/her behalf.
so I have used signer.accessCode = "random value" and passing this value again to end-user/client so that while viewing document he/she needs to place the code which I sent in a different email and its working properly till now.
The problem arises when the recipient views the document and did not sign it and accidentally forward the email to someone else..now that person can view document easily without entering the access code as DocuSign does not ask to place an accessCode second time or once the document is viewed. Is there any config setting or any property in code which I can apply for this case?
I want DocuSign to ask the accessCode popup every time when the end user wants to view it.
Secondly, is there any provision to automatically delete a document from DocuSign if the end user did not sign the document for any specific number of days.
There are two options under Go to Admin > Security Settings that can mitigate this concern. The primary option you want is Recipient Authentication Triggers: Every Time a recipient accesses an envelope. You may also want Login Requirements: Login Required if Signer has an Account.
For the second question, you'll want to set an Envelope Expiration. When an envelope has expired, recipients who have not signed are unable to access it.

Firebase email/password auth + verification weirdness

The use of email verification + email/password authentication doesn't quite work for services that absolutely need email verification before the user can begin using the service.
Let me explain with an example for Google sign in first.
First, the user signs into their Google account (say email is op#op.com), and authorizes your app. Then you create a credential using the tokens received through that, and exchange those tokens with Firebase to log the user into Firebase. The user needs to exist in Firebase for you to use Firebase' email verification service (because the only way to get info on whether an email is verified is to check the currentUser object in the client, so you need a logged in user to check if their email is verified. You can't call an Auth method with an email address to check if it's verified or not). So once you log the user into Firebase, you send them a verification link, and all is good. You can configure the view on your client by checking the user object for email verification. An important point to note here is that some other user who knows this user's email address cannot register using op#op.com on your service: this is because they need to sign into Google with that email to register.
Facebook is similar to Google sign-in in this regard.
However, for email/password, anyone can take someone else's email and create an account with it! And since you cannot send a verification link before the user is registered in Firebase, you're essentially letting anyone in the world "block" email addresses on your service. I was initially trying to ensure email verification before the email is registered into Firebase, but quickly realized that I need the user in Firebase to do any email verification.
Am I missing something, or is this the expected behavior? If this is really how it works, then I might just not allow email/password login in my app.
Side note: another idea I had was to do verification by sending them a 6-digit code, and maintain my own verification system in Firebase. But then I can't add any security rules to it, since any client without a logged in user would need access to it ==> potential system abuse.
Thanks in advance for attempting to read through the long explanation.
So even though an account can be created unverified, you can still block user access using security rules. The latter is what matters and controls access. Here is an example how you can do so with realtime database rules:
{
"rules": {
"users": {
"$user": {
".read": "auth.token.email_verified == true && auth.uid === $user",
".write": "auth.token.email_verified == true && auth.uid === $user"
}
}
}
}
You can also do this on your own if you are verifying the ID token on your server by parsing the token payload and inspecting the email_verified.
So even if the user account is created, unless the user is verified, they will not have access to your app/site data.