Customize email verification page AWS Cognito - amazon-web-services

I am using Amazon Cognito for user authentication. After the user is registered verification email is sent to his email address. After clicking on the email link he is prompted with this in his browser.
How can I customize this page in order to insert a script that will trigger deep links within the mobile application, and also make the page look bit nicer?

You can do that using Cognito triggers.
You can configure a trigger template to define a message with a link to a page you control.
The assets will be stored at: amplify/backend/auth/<your-resource-name>CustomMessage/assets
The documentation has more details
Cognito allows you to configure your User Pool to send an email to
your users when they attempt to register an account. You can configure
this email to contain a link to Cognito’s Hosted UI where the user’s
account will be marked as confirmed.
This trigger template allows you to define an email message with a
link to a static S3 bucket that you control, where the user’s account
will be confirmed and they can then be redirected to a URL of your
choice (presumably your application). The URL will automatically
contain the username as a query string parameters.
Please note that this trigger template will create an S3 resource. The
files that populate the static site are available for edit in
amplify/backend/auth/CustomMessage/assets. They
consist of:
index.html
spinner.js (controls the spinner that appears on the page while users are awaiting confirmation)
style.css
verify.js (the script which performs the verification request)

I was not able to customize the verification page provided by AWS. I created my own UI on my page, which sent the generated code to cognito for verification. For that I needed to:
trigger custom email upon registration
put custom link to verification in the email using the codes provided for the lambda
process the codes on my page
send the codes and username through aws package
Step 1.
In AWS Cognito User Pool, customize workflow with triggers, choose "Custom Message". The triggerSource for verification that I check for are:
event.triggerSource === 'CustomMessage_SignUp' || event.triggerSource === 'CustomMessage_ResendCode'
You can see other trigger sources for CustomMessage here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-message.html
Step 2. The lambda provides parameters for verification for my users: event.request.userAttributes.sub and event.request.codeParameter. Using these to I constructed a link to my page like so:
https://mypage.com?user_name=${event.request.userAttributes.sub}&confirmation_code=${event.request.codeParameter}
Step 3. On my page, I check if the url params for user_name and confirmation_code are present, and display a modal which is supposed to inform the user if the verification went correctly or not.
Using a package "amazon-cognito-identity-js" I process the code and user_name. First I create the user pool:
import { CognitoUserPool } from 'amazon-cognito-identity-js';
//Aws-cognito credentials
const poolData = {
UserPoolId: YOUR_USERPOOL_ID,
ClientId: YOUR_CLIENT_ID,
};
export default new CognitoUserPool(poolData);
Then to process the code I create a user instance:
import { CognitoUser } from 'amazon-cognito-identity-js';
import UserPool from 'utils/UserPool';
const getUser = () => {
return new CognitoUser({
Username: user_name.toLowerCase(),
Pool: UserPool,
});
};
// After that you can process the code:
getUser().confirmRegistration(code, false, function (err, result) {
if (err) {
if (
err.message === 'User cannot be confirmed. Current status is CONFIRMED'
) {
// Handle already confirmed error
} else {
// Handle other errors you want
}
}
// Handle successful verification
});
The account is verified and you can guide the user to the login page or any other.

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

Why can't I get more attributes from google provider via cognito UserInfo endpoint?

I have configured google provider via cognito user pool and I am able to login through google and get user information. And I have added many attributes on the attribute mapping page as shown in below screenshot.
The endpoint I am using to get user info is https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html.
The response data for user info is always:
data: {
identities: '[{"userId":"xxxx","providerName":"Google","providerType":"Google","issuer":null,"primary":true,"dateCreated":1587772412295}]',
email_verified: 'true',
email: 'xxxx#gmail.com',
username: 'Google_1xxxx'
}
Regardless how I update the attribute mappings, I always see above response. Why can't I get additional attributes like picture, given_name, birthday etc. Do I need to set any permission on google side?
In app client setting, I have below configuration:
In authorized scope, I have set: email openid profile

Configure a Custom SMS Message for MFA in AWS Cognito

I Am using AWS Cognito for authentication in a web application.
If a user Forgets their password I have a Lambda Function Trigger that sends a custom email with a link that has the users email address and the verification code in so they can click the link and just enter their new password.
So There is a new requirement that should allow the user to receive an sms, but currently it looks like if you enable MFA for sending the SMS, you can only customise the message in the console area and in the Lambda function,
this event.response.smsMessage does not seem to do anything.
So if the user has phone_number_verified true, it sends the sms without triggering the Lambda function.
exports.handler = function(event, context) {
if(event.triggerSource === "CustomMessage_ForgotPassword") {
var url = 'http://myurl.com/forgotpassword/'+ event.request.userAttributes.email+'/'+event.request.codeParameter
event.response.smsMessage = 'Password Reset: Click the link ' + url + ' or enter Verification Code: ' + event.request.codeParameter
event.response.emailSubject = " Password reset";
event.response.emailMessage = "Custom HTML goes here";
}
context.done(null, event);
};
This is currently the Lambda function configure on custom message trigger in the cognito User pool.
After a long discussion with AWS support, They came to the resolution that my SMS text was more than 140 chars. Yes 140, And then the SMS would not be sent rather the email would. No errors in logs or anything whatsoever.
So they said they will look into adding something in the logs that at least tells you that the SMS was not sent because the character limit was exceeded.

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

AWS Cognito Test Environment

I'm currently working on using AWS Cognito to manage user authentication for our application. One snag I'm running into is figuring out a good way to implement a "test" or "qa" environment.
I have a lot of automated tests for my APIs that will create users with random data. Obviously I don't want to Cognito to send out actual SMS or Email messages in this environment. Also when doing manual testing we will be creating users a lot with fake phone numbers and emails. Is there any way to turn the User Pool in "development" mode where all messages simply get logged some way?
You can write a pre sign up lambda function and auto confirm the user in the lambda function by setting the autoConfirmUser flag. In that case, Cognito doesn't send any SMSes or emails with confirmation codes. Example lambda below from the documentation (http://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html#aws-lambda-triggers-pre-registration-example).
exports.handler = function(event, context) {
// This Lambda function returns a flag to indicate if a user should be auto-confirmed.
// Perform any necessary validations.
// Impose a condition that the minimum length of the username of 5 is imposed on all user pools.
if (event.userName.length < 5) {
var error = new Error('failed!');
context.done(error, event);
}
// Access your resource which contains the list of emails of users who were invited to sign up
// Compare the list of email IDs from the request to the approved list
if(event.userPoolId === "yourSpecialUserPool") {
if (event.request.userAttributes.email in listOfEmailsInvited) {
event.response.autoConfirmUser = true;
}
}
// Return result to Cognito
context.done(null, event);
};
Here is what I did to create a "staging" environment User Pool in AWS Cognito that does not send real notifications to users. There were actually a couple different pieces involved, but I think I was able to get everything covered. That being said, it would sure be nice if Cognito simply provided a User Pool setting to turn off all notifications, that way I don't have to write environment specific logic into my code.
Prevent User Invitations
In our app we use the AdminCreateUser function to create users who get invited by other users. This function will normally send an invitation message to the new user's phone number or email. In order to prevent those invitations, you can provide MessageAction: 'SUPPRESS' as a parameter to the function arguments. Like so:
let params = {
UserPoolId: config.cognitoUserPoolId,
Username: uuid.v4(),
MessageAction: 'SUPPRESS', /* IMPORTANT! */
TemporaryPassword: user.phone_number.slice(-6),
UserAttributes: [
{ Name: 'given_name', Value: user.first_name },
{ Name: 'family_name', Value: user.last_name },
{ Name: 'phone_number', Value: user.phone_number }
]
};
cognito.adminCreateUser(params).promise().then(data => {
console.log(data);
});
Official docs for that here: http://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminCreateUser.html
Prevent User Attribute Update Verfications
In our production app, we want users to have to re-verify their phone number or email if it changes. But in our staging environment we don't actually need this. So uncheck the boxes for email and phone under the "Do you want to require verification of emails or phone numbers?" section in your User Pool settings.