Sling Academy
Home/Node.js/Authentication and Authorization in Express.js with JWT

Authentication and Authorization in Express.js with JWT

Last updated: December 28, 2023

Overview

Authentication and authorization are critical components of web application security. They ensure that only legitimate users can access sensitive resources and perform actions. This tutorial will walk you through the implementation of authentication and authorization in an Express.js application using JSON Web Tokens (JWT). We’ll start with the basics and progress to more advanced topics, including token generation, verification, and the secure handling of sessions.

Getting Started

To begin, make sure you have Node.js and npm installed. Create a new directory for your project and navigate to it in your terminal. Initialize a new npm project with npm init.

$ mkdir auth-jwt-app
$ cd auth-jwt-app
$ npm init -y

Next, install Express.js and required packages:

$ npm install express jsonwebtoken bcryptjs body-parser

Create a file named server.js and set up the basic Express server:

const express = require('express');
const app = express();

app.use(express.json());

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Implementing Authentication

First, we’ll set up the user signup route. This example uses a simple in-memory array to store user records. In production, you would typically use a database.

// At the top of your server.js
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

let users = [];

// Signup route
app.post('/signup', async (req, res) => {
  const { username, password } = req.body;

  // Hash password
  const hashedPassword = await bcrypt.hash(password, 8);

  // Store user
  users.push({ username, password: hashedPassword });

  res.status(201).send('User created');
});

Generating JWT

When a user logs in, we will generate a JWT and send it back to the client:

// At the top of your server.js
const secretKey = 'your_secret_key';

// Login route
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  const user = users.find(u => u.username === username);

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).send('Invalid credentials');
  }

  // Generate token
  const token = jwt.sign({ userId: user.username }, secretKey, { expiresIn: '1h' });

  res.status(200).send({ token });
});

Authorization Middleware

With the JWT generated, we must now verify this token on each protected route. We’ll create middleware to check the validity of the token:

// Middleware for token verification
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) return res.status(401).send('Token required');

  jwt.verify(token, secretKey, (err, user) => {
    if (err) return res.status(403).send('Invalid or expired token');
    req.user = user;
    next();
  });
};

// Protected route example
app.get('/dashboard', authenticateToken, (req, res) => {
  res.status(200).send('Welcome to the dashboard, ' + req.user.userId);
});

Advanced Considerations

We’ve covered the basics, now let’s address some advanced scenarios such as refresh tokens for persistent sessions, and role-based authorization.

To enable refresh tokens, we need an endpoint that can issue a new JWT when the current token is about to expire. This requires us to store refresh tokens securely, often in a persistent database.

Conclusion

In this tutorial, we’ve established a strong foundation for handling authentication and authorization in your Express.js applications using JWT. While our examples have been simplistic, they provide the building blocks for creating a secure authentication system. Remember to always keep your secret keys private, validate your tokens consistently, and consider additional security measures for production environments.

Next Article: How to Get Query String Values in Express.js

Previous Article: How to Use Passport in Express for Authentication

Series: Node.js & Express Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates