Introduction to MERN Stack Authentication
The MERN stack, which includes MongoDB, Express.js, React, and Node.js, is a popular set of technologies for building full-stack web applications. One crucial aspect of any web application is user authentication, which allows users to securely log in and access protected resources.
This guide will walk you through setting up authentication in a MERN stack application, covering everything from creating user models in MongoDB to implementing secure authentication mechanisms using JWT (JSON Web Tokens).
Setting Up MongoDB and User Model
MongoDB is a NoSQL database used in the MERN stack. To implement authentication, we first need to define a user model that will store user credentials such as email, password, and JWT tokens.
Here’s an example of how to create a User model with Mongoose in MongoDB:
Creating the User Schema in MongoDB
The first step is to create a user schema that will be used to store user data, including email, password, and JWT tokens.
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
tokens: [{
token: {
type: String,
required: true
}
}]
});
userSchema.methods.generateAuthToken = async function() {
const user = this;
const token = jwt.sign({ _id: user._id.toString() }, 'secretkey');
user.tokens = user.tokens.concat({ token });
await user.save();
return token;
};
userSchema.pre('save', async function(next) {
const user = this;
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8);
}
next();
});
const User = mongoose.model('User', userSchema);
module.exports = User;User Registration Endpoint
Now, let's create a registration endpoint to allow users to sign up. This will involve hashing the user's password and saving the user data to the database.
const express = require('express');
const router = new express.Router();
const User = require('../models/User');
router.post('/register', async (req, res) => {
try {
const { email, password } = req.body;
const user = new User({ email, password });
await user.save();
const token = await user.generateAuthToken();
res.status(201).send({ user, token });
} catch (e) {
res.status(400).send(e);
}
});
module.exports = router;User Login Endpoint
Next, let's create a login endpoint where users can authenticate themselves using their email and password. We will compare the entered password with the one stored in the database and issue a JWT token upon successful login.
const express = require('express');
const router = new express.Router();
const User = require('../models/User');
router.post('/login', async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) {
return res.status(400).send({ error: 'Invalid login credentials' });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).send({ error: 'Invalid login credentials' });
}
const token = await user.generateAuthToken();
res.send({ user, token });
} catch (e) {
res.status(500).send(e);
}
});
module.exports = router;Protecting Routes with JWT Authentication
To protect certain routes, we can verify the JWT token on incoming requests. This ensures that only authenticated users can access protected resources.
const express = require('express');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '');
const decoded = jwt.verify(token, 'secretkey');
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token });
if (!user) {
throw new Error();
}
req.token = token;
req.user = user;
next();
} catch (e) {
res.status(401).send({ error: 'Please authenticate.' });
}
};
module.exports = auth;Written by
Qasim Ali
Share



