DEV Community

Cover image for Adding Authentication to Node.js API with JWT
EneasLari
EneasLari

Posted on • Edited on • Originally published at eneaslari.com

Adding Authentication to Node.js API with JWT

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
Enter fullscreen mode Exit fullscreen mode
  • 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);
Enter fullscreen mode Exit fullscreen mode

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();
    });
};
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)