Email verification is a crucial aspect of user authentication and security for any online platform. It ensures that the email addresses provided by users during registration are valid and accessible. In this blog post, we'll walk you through building an email verification system using Node.js. We'll cover the following topics:
Let's get started!
Email verification is a process where a system sends an email to the user to confirm their email address. This can help to:
The typical workflow is as follows:
First, let's set up a basic Node.js project.
mkdir email-verification-system
cd email-verification-system
npm init -y
npm install express nodemailer mongoose dotenv jsonwebtoken body-parser cors
Here’s a brief look at the packages we’ll use:
Next, create a file named .env
and add your configuration details:
PORT=3000
MONGO_URI=your_mongodb_connection_uri
SMTP_HOST=smtp.your-email-provider.com
SMTP_PORT=587
[email protected]
SMTP_PASS=your_email_password
JWT_SECRET=your_jwt_secret
Let's start by setting up our server and connecting to MongoDB.
// server.js
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
app.use(express.json());
app.use(require('body-parser').urlencoded({ extended: false }));
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Next, let's create our user model.
// models/User.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
isVerified: { type: Boolean, default: false },
verificationToken: { type: String }
});
module.exports = mongoose.model('User', UserSchema);
Create a utility function for sending verification emails using Nodemailer.
// utils/sendEmail.js
const nodemailer = require('nodemailer');
const { google } = require('googleapis');
const OAuth2 = google.auth.OAuth2;
const sendEmail = async (to, subject, text) => {
const oauth2Client = new OAuth2(
process.env.CLIENT_ID, // ClientID
process.env.CLIENT_SECRET, // Client Secret
"https://developers.google.com/oauthplayground" // Redirect URL
);
oauth2Client.setCredentials({
refresh_token: process.env.REFRESH_TOKEN
});
const accessToken = await oauth2Client.getAccessToken();
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: process.env.EMAIL,
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
refreshToken: process.env.REFRESH_TOKEN,
accessToken: accessToken.token
}
});
const mailOptions = {
from: process.env.EMAIL,
to,
subject,
text
};
await transporter.sendMail(mailOptions);
};
module.exports = sendEmail;
Now let's create the registration route.
// routes/auth.js
const express = require('express');
const User = require('../models/User');
const sendEmail = require('../utils/sendEmail');
const jwt = require('jsonwebtoken');
const router = express.Router();
router.post('/register', async (req, res) => {
const { email, password } = req.body;
try {
const user = new User({ email, password });
const token = jwt.sign({ email }, process.env.JWT_SECRET, { expiresIn: '1h' });
user.verificationToken = token;
await user.save();
const verificationLink = `http://localhost:${process.env.PORT}/verify/${token}`;
await sendEmail(email, 'Email Verification', `Click here to verify your email: ${verificationLink}`);
res.status(200).send('Registration successful! Please check your email to verify your account.');
} catch (error) {
res.status(500).send('Error registering user.');
}
});
module.exports = router;
Next, let's create the verification route.
// routes/verify.js
const express = require('express');
const User = require('../models/User');
const jwt = require('jsonwebtoken');
const router = express.Router();
router.get('/verify/:token', async (req, res) => {
const token = req.params.token;
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const email = decoded.email;
const user = await User.findOne({ email, verificationToken: token });
if (!user) return res.status(400).send('Invalid token.');
user.isVerified = true;
user.verificationToken = null;
await user.save();
res.status(200).send('Email verified successfully!');
} catch (error) {
res.status(500).send('Error verifying email.');
}
});
module.exports = router;
Now, let's integrate our routes into the server.
// server.js
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const authRoutes = require('./routes/auth');
const verifyRoutes = require('./routes/verify');
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
app.use(express.json());
app.use(require('body-parser').urlencoded({ extended: false }));
app.use('/auth', authRoutes);
app.use('/verify', verifyRoutes);
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
http://localhost:3000/auth/register
with JSON data containing an email and password.Setting up an email verification system in Node.js provides an additional layer of security and improves user experience. By following this guide, you can ensure that only legitimate users gain access to your platform. Happy coding!