I'm trying to get signup/login/logout working on my React app using auth0-spa-js following the Quick Start tutorial, and I鈥檓 experiencing a couple problems:
I would expect Auth0 to be "secure by default", but I have some definite concerns about people being able to access my site鈥檚 secure information without even proving they own the email they signed up with. To me, "authenticated" means the user has proven they are who they say they are. Without a verified email, how can that be the case?
If it's up to my app to check whether the user's email has been verified, I think it's critical to add the code for that to the Quick Start. Same thing if it's up to my app to inform the user they need to check their inbox for a verification email.
Struggling with this as well. For now, I've added a check in the callback code to log them out but I'm not really sure this is the best way to handle it.
authComplete$.subscribe(([user, loggedIn]) => {
if (!user.email_verified) {
this.logout('/user/login?showEmailVerificationAlert=true');
} else {
// Redirect to target route after callback processing
this.router.navigate([targetRoute]);
}
});
I could see situations where partial authentication is useful but ideally, this should be a configurable parameter and handled by the API. If not, maybe some documentation on best practices for handling this requirement.
@mcantrell, That's what I intend to do as well (unless Auth0 fixes this), but how do you solve the following?
At this point, I'd like Auth0 to send another verification email, but I don't see a method for this on Auth0Client. Am I supposed to use fetch with the bare API to do this?
Thanks for your feedback. Authentication and verifying emails are not related. There's lots of ways of authenticating, email is just one of them. That's why they're different concepts. If you want to prevent users from signing in without a verified email, you can create a new rule in the Auth0 Dashboard. We even have a template for it:

More info here: https://auth0.com/rules/email-verified
@luisrudge ,
Thanks for pointing me to the Rules feature. That solves the most critical problem (though I'd like to see this at least mentioned in the QuickStart guide).
If a user hasn't verified their email and tries to log in, is there a way to send a new verification email via auth0-spa-js? Or can that also be done via a rule?
The user experience would be unacceptable to have user try to log in, get rejected because of unverified email, then not give them an immediate remedy to fix it.
To answer my own question, it does appear a rule solves the problem. Here's something I just whipped up (warning: not thoroughly tested):
Edit: see below for updated code.
function (user, context, callback) {
if (!user.email_verified) {
resendVerificationEmail();
return callback(new UnauthorizedError("Please check for verification email and follow link before logging in."));
} else {
return callback(null, user, context);
}
function resendVerificationEmail() {
const ManagementClient = require("[email protected]").ManagementClient;
const management = new ManagementClient({
token: auth0.accessToken,
domain: auth0.domain
});
management.sendEmailVerification(
{ user_id: user.user_id },
error => console.log("Unable to send verification email.")
);
}
}
@devuxer thank you so much for your sample code! I'm sure it will help others facing the same concerns.
The above code caused too many verification emails to be sent, so I put in an expiration that limits the amount of verification emails to once per day. Perhaps there's a more elegant way to do this.
Step 1. Add this to a new Pre User Registration hook:
module.exports = function (user, context, cb) {
var response = {};
response.user = user;
user.user_metadata = user.user_metadata || {};
user.user_metadata.emailVerificationSentDate = new Date().valueOf();
console.log(`Set emailVerificationSentDate to ${user.user_metadata.emailVerificationSentDate}`);
cb(null, response);
};
Step 2. Add this to a new Rule
async function (user, context, callback) {
user.user_metadata = user.user_metadata || {};
if (!user.email_verified) {
await resendVerificationEmailIfExpired();
return callback(new UnauthorizedError("Please check for verification email and follow link before logging in."));
} else {
return callback(null, user, context);
}
async function resendVerificationEmailIfExpired() {
const expirationPeriod = 1000 * 60 * 60 * 24; // one day
const lastSent = user.user_metadata.emailVerificationSentDate;
const now = new Date().valueOf();
if (lastSent && now - lastSent < expirationPeriod) return;
const ManagementClient = require("[email protected]").ManagementClient;
const management = new ManagementClient({
token: auth0.accessToken,
domain: auth0.domain
});
const params = { user_id: user.user_id };
try {
const result = await management.sendEmailVerification(params);
user.user_metadata.emailVerificationSentDate = now;
console.log(`Set emailVerificationSentDate to ${user.user_metadata.emailVerificationSentDate}`);
} catch (e) {
console.log(`Unable to send email verification.`);
}
}
}
Most helpful comment
The above code caused too many verification emails to be sent, so I put in an expiration that limits the amount of verification emails to once per day. Perhaps there's a more elegant way to do this.
Step 1. Add this to a new Pre User Registration hook:
Step 2. Add this to a new Rule