disable verification code being sent on email verification on cognito - node.js

userPool.signUp(
userData.email,
userData.password,
attributeList,
[],
async (err, result) => {
if (err) {
failure(new HttpException(500, err.message));
}
let myCredentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: process.env.USER_POOL_ID!,
});
new AWS.Config({
credentials: myCredentials,
region: process.env.AWS_REGION,
});
let cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
cognitoIdentityServiceProvider.adminConfirmSignUp(
{
UserPoolId: process.env.USER_POOL_ID!,
Username: userData.email,
},
function (err, _data) {
if (err) {
failure(err);
}
cognitoIdentityServiceProvider.adminUpdateUserAttributes(
{
UserPoolId: process.env.USER_POOL_ID!,
Username: userData.email,
UserAttributes: [
{
Name: 'email_verified',
Value: 'true',
},
],
},
() => {
console.log('done');
}
);
}
);
if (result) {
const cognitoUser = result.user;
success({ user: cognitoUser, sub: result.userSub });
} else {
failure(
new HttpException(
500,
'Authentication server error, please try again later'
)
);
}
}
);
This is the code by which I am signing up a user and auto verify that user on cognito.
Problem being I have 2 different set of user roles, and one user i am auto confirming but for the other i want them to manually confirm, using the code that is sent by cognito.
Now for the one type of user for which the auto_confirmation is done the email and cofirm user is working perfectly, with one caveat.
The code for verification is being sent even if it's auto verified by admincognito.
How can i disable this on this particualr set of code, so that the other user role can confirm with the code that is being sent via email

Cognito isn't really configurable in this regard. Your escape hatch in this case is the lightly documented custom email sender lambda trigger. Perform whatever checks you want before sending the email through SES (or not).

I solved this issue by creating a pre-signup lambda trigger. And passing in the role to it as a user attribute and then auto verifying email and user based on the role.

Related

how to update custom attributes of user in aws cognito

I'm integrating the stripe into the MERN app. On the stripe webhook call, I need to update the user custom attributes (Cognito). Is there any possible way to find the user using email in the pool and update its custom attributes?
I have tried (function:listUsers) this code to get the user but it doesn't provide the custom variables of the user.
const params = {
UserPoolId: AWS_POOL_ID,
AttributesToGet: ["email"],
};
new Promise((resolve, reject) => {
AWS.config.update({
region: AWS_REGION,
accessKeyId: AWS_ACCESS_PUBLIC,
secretAccessKey: AWS_ACCESS_SECRET,
});
const cognitoIdentityServiceProvider =
new AWS.CognitoIdentityServiceProvider();
cognitoIdentityServiceProvider.listUsers(params, (err, data) => {
if (err) {
console.log("cognito err::", err);
reject(err);
} else {
console.log("cognito data:", data);
resolve(data);
}
});
});
Response:
[
{
Username: '15a2-c98c-43a5-63c',
Attributes: [
{ Name: 'email', Value: 'abc#gmail.com' }
],
UserCreateDate: 2021-12-02T11:33:37.561Z,
UserLastModifiedDate: 2021-12-02T11:35:24.956Z,
Enabled: true,
UserStatus: 'CONFIRMED'
},
{
Username: '15ff633f-41faa9',
Attributes: [
{ Name: 'email', Value: 'abc#gmail.com' }
],,
UserCreateDate: 2021-09-17T14:37:12.943Z,
UserLastModifiedDate: 2021-09-18T04:08:25.443Z,
Enabled: true,
UserStatus: 'CONFIRMED'
}
]
but I need to get and update the custom variables
only email available for finding user
You are passing in email in the AttributesToGet property in the parameters passed to the call to list the user. Based on this documentation, if that array is not included, all attributes will be returned, including the custom attributes from Cognito, which should have the prefix of custom:.
You will also be able to update the user's custom attributes using this function.

How to edit event in google calendar created by service account

I am emailing an HTML link of a Google calendar event generated by Google API to users but they are unable to edit the event, they can only view it when they click the link. I am creating this event with a service account and sharing with other users.
How can I ensure these events are editable in the user's calendar?
This is a link to the code I am using:
const { google } = require('googleapis');
// Provide the required configuration
const CREDENTIALS = JSON.parse(process.env.CREDENTIALS);
const calendarId = process.env.CALENDAR_ID;
// Google calendar API settings
const SCOPES = ['https://www.googleapis.com/auth/calendar.events'];
const calendar = google.calendar({version : "v3"});
const auth = new google.auth.JWT(
CREDENTIALS.client_email,
null,
CREDENTIALS.private_key,
SCOPES,
'email_used_to_configure_the_service_account#gmail.com'
);
auth.authorize(function (err, tokens) {
if (err) {
console.log(err);
return;
} else {
console.log("Successfully connected!");
}
});
//fetching the even object from the db to get evnt.name and co
const saveEvent = {
summary: event.name,
location: event.room.host.location,
description: event.extra,
colorId: 3,
start: {
dateTime: event.startDate,
timeZone: 'Africa/Lagos',
},
end: {
dateTime: event.endDate,
timeZone: 'Africa/Lagos',
},
organizer: {
email: 'email_used_to_configure_the_service_account#gmail.com',
displayName: 'display name',
self: true
},
attendees: [{ email: 'email of recepient of event' }]
//visibility: 'public'
}
async function generateLink(){
try{
const val = await calendar.events.insert({ auth: auth, calendarId: calendarId, resource: saveEvent, sendNotifications: true });
if(val.status === 200 && val.statusText === 'OK'){
console.log('CREATED', val);
return val.data.htmlLink;
}
return console.log('NOT CREATED')
} catch(error){
console.log(`Error ${error}`);
return;
}
}
const link = await generateLink();
let mailData = {
name: user.name ? user.name : user.firstname,
token: `${config.get('platform.url')}/event-accepted/${invite.token}`,
coverImage: event.gallery.link,
eventName: event.name,
hostName: host.name? host.name : host.firstname,
venue: event.venue,
date: event.startDate,
time: event.startDate,
attendees: '',
ticketNo: '',
cost: event.amount,
action: link // htmlLink that takes you to the calendar where user can edit event.
}
mail.sendTemplate({
template: 'acceptEventEmail',
to: u.email.value,
context: mailData
});
Current Behaviour
Expected behaviour
P.S: Code has been added to the question
YOu created the event using a Service account, think of a service account as a dummy user. When it created the event it became the owner / organizer of the event and there for only the service account can make changes to it.
You either need the service account to update it and set someone else as organizer
"organizer": {
"email": "me#gmail.com",
"displayName": "L P",
"self": true
},
Service accounts cannot invite attendees without Domain-Wide Delegation of Authority
In enterprise applications you may want to programmatically access users data without any manual authorization on their part. In Google Workspace domains, the domain administrator can grant to third party applications domain-wide access to its users' data—this is referred as domain-wide delegation of authority. To delegate authority this way, domain administrators can use service accounts with OAuth 2.0.

Nodemailer with E-Mail Templating working locally but not in AWS Lambda environment

I am developing a small webapp that has user accounts. So I want to send E-Mails regarding their registration and E-Mail Address Confirmation.
I am using the Serverless Framework with Express and Node.js as well as Nodemailer with email-templates.
here is the mailer.js function to send a confirmation email:
function sendConfirmation (name, address) {
const transporter = nodemailer.createTransport({
host: 'smtp.strato.de',
port: 465,
secure: true,
auth: {
user: process.env.STRATO_USER,
pass: process.env.STRATO_PASSWORD,
}
});
const email = new Email({
transport: transporter,
send: true,
preview: false,
});
console.log("Sending Email");
email.send({
template: 'confirmation',
message: {
from: 'company',
to: address,
},
locals: {
fname: name,
}
}).then(() => console.log('email has been sent!'));
}
module.exports = {
sendRegister,
sendConfirmation
};
And here is the code of the route. I look for the user in the database and update him to be confirmed. Then I try to send the email.
router.post("/confirmation", async (req, res) => {
userId = req.body.userId;
let userUpdated = false;
let updatedUser;
updatedUser = await User.findByIdAndUpdate({_id: userId}, {"confirmed": true}, function (err, result) {
if(err){
res.send(err)
}
else{
userUpdated = true;
}
});
if (userUpdated) {
await sendConfirmation(updatedUser.name, updatedUser.email);
res.json({error: null, data: "User confirmed"});
}
});
If I test this with app.listen on localhost I receive the E-Mail without any problems. As soon as I deploy it to AWS with Serverless, the user gets updated in the DB, but the E-Mail is not send. It seems that Lambda does not wait until the promise of the email.send() is there? I also tried to explicitly allow the Lambda function to communicate with port 465 on outbound traffic. No luck.
In the logs of the Lambda function no error is shown, but also no confirmation of the sent email.
Has anyone an idea what I am missing? Thank you very much!
EDIT 1:
I just found out, that if I use await sleep(2000) with an according function
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
right after calling the sendConfirmation function and it works without problems. It seems, that the sendConfirmation function will not wait for the promise of email.send. Any idea how to solve this? I am fairly new to promises.
Thanks in advance!

Creating user with email and password in admin console results in anonymous user

I'm creating users using the admin SDK and I'm wanting them to be able to login with email and password. For some reason when I create users through the client using only email and password, the user can login using those credentials, but when I create a user using the admin SDK, the user is shown as anonymous in the auth dashboard, and the user can't login using their email and password. No errors are shown client side or Firebase side.
How can I create a Firebase user using the admin SDK and have that user linked to email authentication?
Node:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.createUser = functions.https.onRequest(async (req, res) => {
//grab the email and password parameters
await admin.auth().createUser({
email: req.query.email,
password: req.query.password
})
//create the user
.then(function(userRecord) {
const child = userRecord.uid;
console.log('Successfully created new user:', userRecord.uid);
res.json({
status: 201,
data: {
"message": userRecord.uid
}
});
})
//handle errors
.catch(function(error) {
console.log();
res.json({
status: 500,
data: {
"error": 'error creating user: ', error
}
});
});
});
Swift:
func createChild(for parent: Parent,
with firstName: String,
lastName: String,
displayName: String?,
chores: [Chore]?,
username: String,
password: String,
completion: #escaping () -> Void = { }) {
let funcCallDict = [
"email": username,
"password": password
]
functions.httpsCallable(addChildIdentifier).call(funcCallDict) { (result, error) in
if let error = error {
NSLog("error: adding child with firebase function: \(error)")
completion()
return
}
}
completion()
}
Your function is an HTTP type trigger:
exports.createUser = functions.https.onRequest
But you're trying to invoke it as a callable type trigger:
functions.httpsCallable(addChildIdentifier).call(funcCallDict)
(Note that a callable trigger would be defined with onCall, not onRequest.)
As you can see from the documentation links, they are not the same thing. You are probably invoking the HTTP trigger, and it's not actually getting the arguments you expect from the client, since the protocol is different between them. Try logging req.query.email in the function to see what I mean.
You will have to either make your function a proper callable so it can be invoked from the client using the provided library, or change the way you invoke it on the client to use a regular http library instead of the Firebase library.

How to confirm email address using express/node?

I'm trying to build verification of email address for users, to verify their email is real. What package should I use to confirm the email address of the user? So far Im using mongoose and express
Code Example
var UserSchema = new mongoose.Schema({
email: { type: String, unique: true, lowercase: true }
password: String
});
var User = mongoose.model('User', UserSchema);
app.post('/signup', function(req, res, next) {
// Create a new User
var user = new User();
user.email = req.body.email;
user.password = req.body.password;
user.save();
});
In the app.post codes, how do i confirm the email address of the user?
What you're looking for is called "account verification" or "email verification". There are plenty of Node modules that can perform this, but the principle goes like this:
Your User model should have an active attribute that is false by default
When the user submits a valid signup form, create a new User (who's active will be false initially)
Create a long random string (128 characters is usually good) with a crypto library and store it in your database with a reference to the User ID
Send an email to the supplied email address with the hash as part of a link pointing back to a route on your server
When a user clicks the link and hits your route, check for the hash passed in the URL
If the hash exists in the database, get the related user and set their active property to true
Delete the hash from the database, it is no longer needed
Your user is now verified.
var express=require('express');
var nodemailer = require("nodemailer");
var app=express();
/*
Here we are configuring our SMTP Server details.
STMP is mail server which is responsible for sending and recieving email.
*/
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "Your Gmail ID",
pass: "Gmail Password"
}
});
var rand,mailOptions,host,link;
/*------------------SMTP Over-----------------------------*/
/*------------------Routing Started ------------------------*/
app.get('/',function(req,res){
res.sendfile('index.html');
});
app.get('/send',function(req,res){
rand=Math.floor((Math.random() * 100) + 54);
host=req.get('host');
link="http://"+req.get('host')+"/verify?id="+rand;
mailOptions={
to : req.query.to,
subject : "Please confirm your Email account",
html : "Hello,<br> Please Click on the link to verify your email.<br>Click here to verify"
}
console.log(mailOptions);
smtpTransport.sendMail(mailOptions, function(error, response){
if(error){
console.log(error);
res.end("error");
}else{
console.log("Message sent: " + response.message);
res.end("sent");
}
});
});
app.get('/verify',function(req,res){
console.log(req.protocol+":/"+req.get('host'));
if((req.protocol+"://"+req.get('host'))==("http://"+host))
{
console.log("Domain is matched. Information is from Authentic email");
if(req.query.id==rand)
{
console.log("email is verified");
res.end("<h1>Email "+mailOptions.to+" is been Successfully verified");
}
else
{
console.log("email is not verified");
res.end("<h1>Bad Request</h1>");
}
}
else
{
res.end("<h1>Request is from unknown source");
}
});
/*--------------------Routing Over----------------------------*/
app.listen(3000,function(){
console.log("Express Started on Port 3000");
});
Follow the code example, you can use nodemailer to send the link, and then verify it.
Here is a link: https://codeforgeek.com/2014/07/node-email-verification-script/
Step 1:
User Model
var userSchema = new mongoose.Schema({
email: { type: String, unique: true },
isVerified: { type: Boolean, default: false },
password: String,
});
Token Model
const tokenSchema = new mongoose.Schema({
_userId: { type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
token: { type: String, required: true },
expireAt: { type: Date, default: Date.now, index: { expires: 86400000 } }
});
Step 2: Login
exports.login = function(req, res, next) {
User.findOne({ email: req.body.email }, function(err, user) {
// error occur
if(err){
return res.status(500).send({msg: err.message});
}
// user is not found in database i.e. user is not registered yet.
else if (!user){
return res.status(401).send({ msg:'The email address ' + req.body.email + ' is not associated with any account. please check and try again!'});
}
// comapre user's password if user is find in above step
else if(!Bcrypt.compareSync(req.body.password, user.password)){
return res.status(401).send({msg:'Wrong Password!'});
}
// check user is verified or not
else if (!user.isVerified){
return res.status(401).send({msg:'Your Email has not been verified. Please click on resend'});
}
// user successfully logged in
else{
return res.status(200).send('User successfully logged in.');
}
});
});
Step 3: Sign Up
exports.signup = function(req, res, next) {
User.findOne({ email: req.body.email }, function (err, user) {
// error occur
if(err){
return res.status(500).send({msg: err.message});
}
// if email is exist into database i.e. email is associated with another user.
else if (user) {
return res.status(400).send({msg:'This email address is already associated with another account.'});
}
// if user is not exist into database then save the user into database for register account
else{
// password hashing for save into databse
req.body.password = Bcrypt.hashSync(req.body.password, 10);
// create and save user
user = new User({ name: req.body.name, email: req.body.email, password: req.body.password });
user.save(function (err) {
if (err) {
return res.status(500).send({msg:err.message});
}
// generate token and save
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
token.save(function (err) {
if(err){
return res.status(500).send({msg:err.message});
}
// Send email (use credintials of SendGrid)
var transporter = nodemailer.createTransport({ service: 'Sendgrid', auth: { user: process.env.SENDGRID_USERNAME, pass: process.env.SENDGRID_PASSWORD } });
var mailOptions = { from: 'no-reply#example.com', to: user.email, subject: 'Account Verification Link', text: 'Hello '+ req.body.name +',\n\n' + 'Please verify your account by clicking the link: \nhttp:\/\/' + req.headers.host + '\/confirmation\/' + user.email + '\/' + token.token + '\n\nThank You!\n' };
transporter.sendMail(mailOptions, function (err) {
if (err) {
return res.status(500).send({msg:'Technical Issue!, Please click on resend for verify your Email.'});
}
return res.status(200).send('A verification email has been sent to ' + user.email + '. It will be expire after one day. If you not get verification Email click on resend token.');
});
});
});
}
});
});
Step 4: Verify Account
// It is GET method, you have to write like that
// app.get('/confirmation/:email/:token',confirmEmail)
exports.confirmEmail = function (req, res, next) {
Token.findOne({ token: req.params.token }, function (err, token) {
// token is not found into database i.e. token may have expired
if (!token){
return res.status(400).send({msg:'Your verification link may have expired. Please click on resend for verify your Email.'});
}
// if token is found then check valid user
else{
User.findOne({ _id: token._userId, email: req.params.email }, function (err, user) {
// not valid user
if (!user){
return res.status(401).send({msg:'We were unable to find a user for this verification. Please SignUp!'});
}
// user is already verified
else if (user.isVerified){
return res.status(200).send('User has been already verified. Please Login');
}
// verify user
else{
// change isVerified to true
user.isVerified = true;
user.save(function (err) {
// error occur
if(err){
return res.status(500).send({msg: err.message});
}
// account successfully verified
else{
return res.status(200).send('Your account has been successfully verified');
}
});
}
});
}
});
});
Step 5: Resend Link
exports.resendLink = function (req, res, next) {
User.findOne({ email: req.body.email }, function (err, user) {
// user is not found into database
if (!user){
return res.status(400).send({msg:'We were unable to find a user with that email. Make sure your Email is correct!'});
}
// user has been already verified
else if (user.isVerified){
return res.status(200).send('This account has been already verified. Please log in.');
}
// send verification link
else{
// generate token and save
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
token.save(function (err) {
if (err) {
return res.status(500).send({msg:err.message});
}
// Send email (use credintials of SendGrid)
var transporter = nodemailer.createTransport({ service: 'Sendgrid', auth: { user: process.env.SENDGRID_USERNAME, pass: process.env.SENDGRID_PASSWORD } });
var mailOptions = { from: 'no-reply#example.com', to: user.email, subject: 'Account Verification Link', text: 'Hello '+ user.name +',\n\n' + 'Please verify your account by clicking the link: \nhttp:\/\/' + req.headers.host + '\/confirmation\/' + user.email + '\/' + token.token + '\n\nThank You!\n' };
transporter.sendMail(mailOptions, function (err) {
if (err) {
return res.status(500).send({msg:'Technical Issue!, Please click on resend for verify your Email.'});
}
return res.status(200).send('A verification email has been sent to ' + user.email + '. It will be expire after one day. If you not get verification Email click on resend token.');
});
});
}
});
});
You can take help from this link:https://medium.com/#slgupta022/email-verification-using-sendgrid-in-node-js-express-js-mongodb-c5803f643e09
I would like to present a slightly different approach from the ones proposed.
This method does not put the hash into the database (therefore less interaction with it)
You don't need to register the hash in the database. Here's an overview after receiving a registration request:
You encode the user id + registration time
You send the token to the user
When the user triggers his registration request, you decode the token.
Because The decoded token contains the user id + the time, you can
mark the user as registered by increasing their role
(registered, subscriber, admin, etc.) for instance
Translated into code, you would have something like this:
1- Encode the token
function encodeRegistrationToken()
{
// jsonweb automatically adds a key that determines the time, but you can use any module
const jwt = require('jsonwebtoken');
// The information we need to find our user in the database (not sensible info)
let info = {id: yourUserId};
// The hash we will be sending to the user
const token = jwt.sign(info, "yoursecretkey");
return token;
}
// ...
let token = encodeRegistrationToken();
2- Send token to the user via any appropriate way
// Your implementation of sending the token
sendTokenToUser(token);
3- Decode the token
function decodeRegistrationToken(token)
{
const jwt = require('jsonwebtoken');
let decoded = jwt.verify(token, "yoursecretkey");
let userId = decoded.id;
// Check that the user didn't take too long
let dateNow = new Date();
let tokenTime = decoded.iat * 1000;
// Two hours
let hours = 2;
let tokenLife = hours * 60 * 1000;
// User took too long to enter the code
if (tokenTime + tokenLife < dateNow.getTime())
{
return {
expired: true
};
}
// User registered in time
return {
userID
};
}
4 - Update your database
Upgrade the user role to subscriber
or
Set their "register" key to true
Quick note: You can further encode the user id when encoding your token if you want (it's easily accessible).
I spent a lot of time figuring out the perfect way to send confirmation mail. Here is the method I used.
Libraries
const jwt = require('jsonwebtoken');
const nodemailer = require("nodemailer");
Step 1
Encode the user id in a jwt token with an expiration date
var date = new Date();
var mail = {
"id": user.id,
"created": date.toString()
}
const token_mail_verification = jwt.sign(mail, config.jwt_secret_mail, { expiresIn: '1d' });
var url = config.baseUrl + "verify?id=" + token_mail_verification;
Step 2
Send the token to the user email address using nodemailer library
let transporter = nodemailer.createTransport({
name: "www.domain.com",
host: "smtp.domain.com",
port: 323,
secure: false, // use SSL
auth: {
user: "user#domain.com", // username for your mail server
pass: "Password", // password
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: '"NAME" <user#domain.com>', // sender address
to: user.email, // list of receivers seperated by comma
subject: "Account Verification", // Subject line
text: "Click on the link below to veriy your account " + url, // plain text body
}, (error, info) => {
if (error) {
console.log(error)
return;
}
console.log('Message sent successfully!');
console.log(info);
transporter.close();
});
Step 3
Accept the verification link
app.get('/verify', function(req, res) {
token = req.query.id;
if (token) {
try {
jwt.verify(token, config.jwt_secret_mail, (e, decoded) => {
if (e) {
console.log(e)
return res.sendStatus(403)
} else {
id = decoded.id;
//Update your database here with whatever the verification flag you are using
}
});
} catch (err) {
console.log(err)
return res.sendStatus(403)
}
} else {
return res.sendStatus(403)
}
})
Step 4
Have a coffee and THANK ME for saving your so much time
PS: This nodemailer SMTP method will even work with your hosting. So no need to go for third party. You can also find ways to use gmail with nodemailer.
if you are just testing on your local machine, one simple way of understanding how to do it can be :
Assuming you already know sending mails through nodemailer..
Once user signs up, after storing sign-up data in your database, on your server side take user email from sign-up data received and a random generated number and build a custom url with the address of page where user will be directed after he/she clicks on the link given in mail.
var customUrl = "http://"+ your host + "/" + your verification web-page + "?email=" + userEmail + "&id=" + randomNumber;
An example can be:
var userEmail = someone#example.com
var host = localhost:8080
var directWebPage = verifyUserEmail.html
var randomNumber = // generate with math.random() // lets say 111
Putting in above format of customUrl it looks something like this
customUrl:http://localhost:8080/verifyUserEmail.htmlemail=someone#example.com&id=111
Save this customUrl somewhere (probably in your database)
Now, send an email to user with email body containing this cutomUrl link.
Click to verify your email
When user clicks on the link he/she will be directed to verifyUserEmail.html page and when that happens you can extract the page url containing email and id information
For example in angular I go like this-
var urlVerifyData = $location.url(); or $location.absUrl();
Now extract email form urlVerifyData string using javascript string methods
Request your server with this email and urlVerifyData
Now query your database for this email and verify previously stored customUrl with user's urlVerifyData
If they match, hola ! You got yourself a genuine user !!!
I came across a Reddit post where one explained that one click on the link is not sufficient and might lead to errors and a failure of the verification. The logic is simple and legit, when the email containing the link is received, there might be link scanners (bots) on the SMTP server (Outlook, Gmail etc). Just like when you past a link on major social platforms, there is always a bot that hits the link. I did not try it myself but I believe Outlook scans some links (when you copy past a link it is converted to a thumbnail with page's content).
So this process oblige you to do a verification by two steps, maybe when the user clicks, he needs to past his own password used for signup (looks fine). Or provide a one time password with the email so that the user along with the verification link (maybe split then re-concat) the same token you send for verification and ask the user to enter that second part (this seems easier).
function generateLink() {
var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
var token = '';
for (var i = 16; i > 0; --i) {
var rand = Math.round(Math.random() * (chars.length - 1))
token += chars[rand];
}
var link = "http://localhost" + "/verify?id=" + token;
return link;
}
// npm install #sendGrid/mail --save
//library for generating link using SendGrid
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey("SENDGRID_API_KEY"); //create an account on sendgrid and get an API key
// generated link is send to the user's email for email verification
let sendVerifyEmailLink = (req, res) => {
var link = generateLink();
const msg = {
to: 'test#gmail.com',
from: 'test#gmail.com',
subject: 'Account Verifictaion',
text: 'Hello,\n\n' + 'Please verify your account by clicking the link:\/\/\n',
html: 'Hello,\n\n <br> Please verify your account by clicking the link: \n <br> <strong><a href = ' + link + '>http:\/\/ Click here to verify the given Link </a></strong>.\n .<br>Thanks<br>',
};
sgMail.send(msg).then(() => { }, error => {
console.error(error);
if (error.response) {
console.error(error.response.body)
}
});
console.log(msg)
}

Resources