Adding Authentication to Node.js API with JWT

Adding Authentication to Node.js API with JWT

Created by eneaslari 21/9/2023

nodejs

Previous articles:

How to Make API using NodeJS and Express

Enhancing Our Node.js API: Hot Reloading with Nodemon, Bundling with Webpack & Using ES6

1. JWT Overview

JSON Web Tokens (JWT) offer a compact and self-contained way to securely transmit information between parties as a JSON object. In authentication, when the user logs in using their credentials, a server-side application provides a signed token to the client. The client then uses this token to access protected routes or resources.

2. Setting up JWT Authentication

Step 1: Install the necessary packages:

npm install jsonwebtoken bcryptjs
  • jsonwebtoken - For generating and verifying JWTs.
  • bcryptjs - For hashing and checking user passwords.

Step 2: Set up a User Model with Password Hashing (models/user.js):

If not already set, add a password field to the user schema. Then, implement password hashing using bcrypt:

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
    // ... other fields ...
    password: {
        type: String,
        required: true,
    },
});

// Hash password before saving
userSchema.pre('save', async function(next) {
    if (this.isModified('password')) {
        this.password = await bcrypt.hash(this.password, 10);
    }
    next();
});

module.exports = mongoose.model('User', userSchema);

Step 3: Implement Signup and Login Routes:

  • Signup:

    const bcrypt = require('bcryptjs');
    const User = require('../models/user');
    
    exports.signup = async (req, res) => {
        const user = new User(req.body);
        await user.save();
        res.status(201).json({ message: "User registered successfully!" });
    };
    
  • Login:

    const jwt = require('jsonwebtoken');
    
    exports.login = async (req, res) => {
        const { email, password } = req.body;
        const user = await User.findOne({ email });
    
        if (!user || !await bcrypt.compare(password, user.password)) {
            return res.status(401).json({ error: "Invalid email or password" });
        }
    
        const token = jwt.sign({ userId: user.id }, 'YOUR_SECRET_KEY', { expiresIn: '1h' });
    
        res.json({ token });
    };
    

Remember to replace 'YOUR_SECRET_KEY' with your actual secret key.

3. Protecting Routes

To protect routes, we create a middleware that verifies the JWT:

Middleware (middlewares/auth.js):

const jwt = require('jsonwebtoken');

exports.verifyToken = (req, res, next) => {
    const token = req.headers['authorization'];

    if (!token) {
        return res.status(403).json({ error: 'No token provided' });
    }

    jwt.verify(token, 'YOUR_SECRET_KEY', (err, decoded) => {
        if (err) {
            return res.status(401).json({ error: 'Unauthorized' });
        }
        req.userId = decoded.userId;
        next();
    });
};

Now, apply this middleware to any route you want to protect. For instance, to protect a route that fetches user data:

const express = require('express');
const { verifyToken } = require('../middlewares/auth');

const router = express.Router();

router.get('/protectedRoute', verifyToken, (req, res) => {
    // Your protected route logic here
});

module.exports = router;

With the setup above, only authenticated users with valid JWTs can access the protected routes. Remember to handle security considerations, such as storing JWTs securely in frontend applications, using HTTPS, and frequently rotating your secret keys.

With this, your Node.js and Express API now has a robust authentication mechanism using JWTs and can protect routes from unauthorized access.

More to read


My New Plan: Making a Mini-Game Every Week
21/2/2025

This week, I realized that working on big projects can sometimes feel slow, and it’s easy to lose motivation. So, I came up with a new plan—I’ll create and release a small game every week!

Making Tic-Tac-Toe and Sudoku in Just a Few Hours
20/2/2025

This week, I decided to take a break from my main game project and create something simple: **a Tic-Tac-Toe and a Sudoku game**.

How I Made My Game Development Workflow Stress-Free
19/2/2025

Game development can be overwhelming, especially when working on multiple tasks without a clear plan. For a while, I was struggling to organize my thoughts and decide what to focus on next

Designing Fun and Engaging Game Levels
18/2/2025

Creating levels for a game sounds simple, but it comes with its own set of challenges.