- SMTP_HOST
- SMTP_PORT
- SMTP_USERNAME
- SMTP_PASSWORD
- AUTH0_DOMAIN
- AUTH0_CLIENT_ID
- AUTH0_CLIENT_SECRET
Make sure the AUTH0_CLIENT_ID has client_credentials grant.
read:users
update:users
update:users_app_metadata
create:user_tickets
read:email_templates
Make sure the AUTH0_CLIENT_ID has client_credentials grant.
read:users
update:users
update:users_app_metadata
create:user_tickets
read:email_templates
function sendVerificationEmail(user, context, callback) { | |
// Perform any asynchronous actions, e.g. send notification to Slack. | |
var nodemailer = require('nodemailer'); | |
var tools = require('auth0-extension-tools@1.3.1'); | |
var async = require('async'); | |
var Liquid = require("liquid-node"); | |
var engine = new Liquid.Engine(); | |
/* | |
* Constants | |
*/ | |
var EMAIL_FROM = "{REPLACE_WITH_EMAIL_FROM_ADDRESS}"; | |
var EMAIL_SUBJECT = "Verify your Email"; | |
/* | |
* SMTP Transport object | |
*/ | |
var smtpConfig = { | |
host: configuration.SMTP_HOST, | |
port: configuration.SMTP_PORT, | |
secure: false, // upgrade later with STARTTLS | |
auth: { | |
user: configuration.SMTP_USERNAME, | |
pass: configuration.SMTP_PASSWORD | |
} | |
}; | |
var CLIENTS_TO_SEND_VERIFICATION_EMAIL = ['REPLACE_WITH_YOUR_CLIENT_ID']; | |
// run only for the specified clients | |
if (CLIENTS_TO_SEND_VERIFICATION_EMAIL.indexOf(context.clientID) !== -1 && user.email_verified === false) { | |
// init workflow | |
workflow(user, context, callback); | |
} else { | |
callback(null, user, context); | |
} | |
var transporter = nodemailer.createTransport(smtpConfig); | |
var user_id = user.user_id; | |
/* | |
* 1. Get Auth0 Management Token | |
* 2. Update user app_metadata | |
* 3. create verification email ticket | |
* 4. get verification email template | |
* 5. populate template with data | |
* 6. send email | |
*/ | |
function callAuth0ManagementApi(stage, options, cb) { | |
tools.managementApi.getClient({domain: configuration.AUTH0_DOMAIN, clientId: configuration.AUTH0_CLIENT_ID, clientSecret: configuration.AUTH0_CLIENT_SECRET}) | |
.then(function(client) { | |
switch (stage) { | |
case 'update_user': | |
var app_metadata = user.app_metadata || {}; | |
var code = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); | |
var codeDate = new Date(); | |
app_metadata.code = code; | |
app_metadata.codeDate = codeDate; | |
user.app_metadata = app_metadata; | |
client.users.updateAppMetadata({id: user_id}, app_metadata, function (error, u) { | |
if (error) return callback(error); | |
return cb(null, options); | |
}); | |
break; | |
case 'create_verification_ticket': | |
var data = {}; | |
data.user_id = user_id; | |
if (options.template.resultUrl) { | |
data.result_url = options.template.resultUrl; | |
} | |
console.log(data); | |
client.tickets.verifyEmail(data, function (error, ticket) { | |
if (error) return callback(error); | |
options.ticket = ticket; | |
return cb(null, options); | |
}); | |
break; | |
case 'get_verification_email_template': | |
client.emailTemplates.get({name: "verify_email"}, function (error, template) { | |
if (error) return callback(error); | |
options.template = template; | |
return cb(null, options); | |
}); | |
break; | |
} | |
}) | |
.catch(error => console.log(error)); | |
} | |
function updateUserAppMetadata(options, cb) { | |
console.log("3. updateUserAppMetadata>>>"); | |
callAuth0ManagementApi('update_user', options, cb); | |
} | |
function getVerifyEmailTemplate(options, cb) { | |
console.log("2. getVerifyEmailTemplate>>>"); | |
callAuth0ManagementApi('get_verification_email_template', options, cb); | |
} | |
function createVerificationTicket (options, cb) { | |
/* | |
* https://auth0.com/docs/api/management/v2#!/Tickets/post_email_verification | |
* var data = { | |
* user_id: '{USER_ID}', | |
* result_url: '{REDIRECT_URL}' // Optional redirect after the ticket is used. | |
* }; | |
*/ | |
console.log("4. createVerificationTicket>>>"); | |
callAuth0ManagementApi('create_verification_ticket', options, cb); | |
} | |
function populateEmailTemplate(options, cb) { | |
engine | |
.parseAndRender(options.template.body, { url: options.ticket.ticket, user: user }) | |
.then(function(renderedTemplate) { | |
console.log(renderedTemplate); | |
options.renderedTemplate = renderedTemplate; | |
cb(null, options); | |
}) | |
.catch(error => cb(error)); | |
} | |
function sendVerificationEmail(options, cb) { | |
var mailOptions = { | |
from : EMAIL_FROM, | |
to: user.email, | |
subject: EMAIL_SUBJECT, | |
html: options.renderedTemplate | |
}; | |
transporter.sendMail(mailOptions, function(error, response){ | |
if(error){ | |
console.log(error); | |
callback(error); | |
}else{ | |
console.log("Message sent: " + response.message); | |
cb(null, 'done'); | |
} | |
// if you don't want to use this transport object anymore, uncomment following line | |
//smtpTransport.close(); // shut down the connection pool, no more messages | |
}); | |
} | |
function workflow(user, context, cb) { | |
async.waterfall([ | |
async.apply(updateUserAppMetadata, {}), | |
getVerifyEmailTemplate, | |
createVerificationTicket, | |
populateEmailTemplate, | |
sendVerificationEmail | |
], function (err, result) { | |
console.log('err', err); | |
console.log('result: ', result); | |
}); | |
return cb(new UnauthorizedError('We have sent you a email to confirm your identity. Please verify your email and login.')); | |
} | |
} | |