In this tutorial, you’ll learn how to implement authentication in your Express API using JWT. By the end of today’s lesson, users will be able to register, log in, and access protected routes using a token-based authentication system.
What You Will Learn Today:
- Installing and setting up JWT for authentication
- Creating user registration and login routes
- Generating JWT tokens upon successful login
- Protecting API routes using JWT middleware
- Testing authentication with Postman
Step 1: Installing JWT and Bcrypt
Before we implement authentication, we need two libraries:
- JWT: For generating and verifying tokens.
- Bcrypt: For securely hashing passwords before storing them in the database.
- Install these packages by running the following command:
npm install jsonwebtoken bcryptjs
Step 2: Creating User Registration and Login Routes
Let’s first set up routes for user registration and login. We’ll hash the password using bcrypt and generate a JWT upon successful login.
User Registration
- Open
routes/users.js
and add the following route for user registration:
const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const router = express.Router();
const User = require('../models/User');
const userController = require('../controllers/userController');
// Register a new user
router.post('/register', async (req, res) => {
const { name, email, password } = req.body;
try {
// Check if the user already exists
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ message: 'User already exists' });
}
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Create a new user
const newUser = new User({ name, email, password: hashedPassword });
const savedUser = await newUser.save();
res.status(201).json(savedUser);
} catch (error) {
res.status(500).json({ message: 'Error registering user', error });
}
});
Explanation:
- bcrypt.hash(): This function hashes the user’s password with a salt, ensuring that passwords are stored securely.
- Check for existing user: We first check if a user with the given email already exists to prevent duplicate registrations.
User Login
Next, let’s create a route for user login. When the user logs in, we’ll verify their email and password, and if successful, we’ll generate a JWT.
- Add the following route for login:
// User login
router.post('/login', async (req, res) => {
const { email, password } = req.body;
try {
// Check if the user exists
const user = await User.findOne({ email });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
// Check if the password is correct
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ message: 'Invalid credentials' });
}
// Generate a JWT
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token });
} catch (error) {
res.status(500).json({ message: 'Error logging in', error });
}
});
Explanation:
- bcrypt.compare(): This function compares the provided password with the hashed password stored in the database.
- jwt.sign(): This generates a JWT token, signed with a secret key (
process.env.JWT_SECRET
). The token will expire in 1 hour.
Step 3: Protecting Routes with JWT Middleware
Now that we have JWT tokens, we can protect certain routes by ensuring that the user provides a valid token before accessing those routes. We’ll create middleware to verify the token.
Creating JWT Middleware
- Inside your project directory, create a new folder called
middleware
and a file calledauth.js
.
mkdir middleware
touch middleware/auth.js
- Open
middleware/auth.js
and add the following code to verify JWT tokens:
const jwt = require('jsonwebtoken');
const auth = (req, res, next) => {
const token = req.header('x-auth-token');
// Check if token exists
if (!token) {
return res.status(401).json({ message: 'No token, authorization denied' });
}
try {
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded; // Add the decoded user ID to the request object
next();
} catch (error) {
res.status(401).json({ message: 'Invalid token' });
}
};
module.exports = auth;
Explanation:
jwt.verify()
: Verifies the provided token using the secret key. If valid, it adds the user ID to the request object (req.user
).next()
: Passes control to the next middleware or route handler if the token is valid.
Protecting Routes
Let’s protect the GET /api/users route so that only authenticated users can access it.
- Open
routes/users.js
and modify theGET
route to use theauth
middleware:
const auth = require('../middleware/auth');
// Get all users (protected route)
router.get('/', auth, userController.getAllUsers);
Explanation:
- The
auth
middleware is added before thegetAllUsers
controller. This ensures that the token is verified before accessing the route.
Step 4: Testing Authentication with Postman
Let’s test the registration, login, and protected routes using Postman.
1. Register a New User
- Open Postman and make a POST request to
http://localhost:5000/api/users/register
with the following JSON body:
{
"name": "John Doe",
"email": "[email protected]",
"password": "password123"
}
- If the registration is successful, you should receive a response with the newly created user.
2. Log In as the Registered User
- Make a POST request to
http://localhost:5000/api/users/login
with the following JSON body:
{
"email": "[email protected]",
"password": "password123"
}
- If the login is successful, you’ll receive a response containing the JWT token:
{
"token": "your_jwt_token_here"
}
3. Access the Protected Route
- Now, let’s access the protected GET /api/users route. In Postman:
- Set the request method to GET.
- URL:
http://localhost:5000/api/users
. - In the Headers section, add a header:
- Key:
x-auth-token
- Value:
your_jwt_token_here
(replace with the token you received from the login request).
- Key:
- Send the request, and you should receive a list of users if the token is valid.
If you try to access the route without a token or with an invalid token, you’ll receive a 401 Unauthorized
error.
Step 5: Recap and Summary
In this tutorial, you learned how to implement authentication using JWT (JSON Web Tokens) in your Express API. Here’s a quick summary of what you’ve done:
- Installed
jsonwebtoken
andbcryptjs
for handling authentication and password hashing. - Created user registration and login routes.
- Generated JWT tokens upon successful login.
- Created middleware to protect routes using JWT.
- Tested the authentication flow using Postman.
With authentication in place, your API is now secured, and only authorized users can access protected routes!
Next Up: Day 5 – Implementing Middleware and Error Handling
In Day 5, we’ll dive into adding custom middleware for logging, validation, and error handling in your Express API. This will help you manage errors and maintain clean, consistent responses.
Stay tuned for more advanced features tomorrow!