Close Menu
Soshace Digital Blog

    Subscribe to Updates

    Get The Latest News, Updates, And Amazing Offers

    What's Hot
    Interview

    Interview With Oleg – Soshace Team

    LinkedIn

    Transforming LinkedIn Connections into Effective Sales Leads

    Beginners

    Automating and Scheduling Tasks Using Python

    Important Pages:
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Today's Picks:
    • Scaling Success: Monitoring Indexation of Programmatic SEO Content
    • Leveraging Influencers: Key Drivers in New Product Launches
    • How Privacy-First Marketing Will Transform the Industry Landscape
    • The Impact of Social Proof on Thought Leadership Marketing
    • Balancing Value-Driven Content and Promotional Messaging Strategies
    • Top Influencer Marketing Platforms to Explore in 2025
    • Emerging Trends in Marketing Automation and AI Tools for 2023
    • Strategies to Mitigate Duplicate Content in Programmatic SEO
    Sunday, September 28
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Soshace Digital Blog
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Services
    • SaaS & Tech

      Maximizing Efficiency: How SaaS Lowers IT Infrastructure Costs

      August 27, 2025

      Navigating Tomorrow: Innovations Shaping the Future of SaaS

      August 27, 2025

      Maximizing Impact: Strategies for SaaS & Technology Marketing

      August 27, 2025
    • AI & Automation

      Enhancing Customer Feedback Analysis Through AI Innovations

      August 27, 2025

      Navigating the Impact of AI on SEO and Search Rankings

      August 27, 2025

      5 Automation Hacks Every Home Service Business Needs to Know

      May 3, 2025
    • Finance & Fintech

      Critical Missteps in Finance Marketing: What to Avoid

      August 27, 2025

      Analyzing Future Fintech Marketing Trends: Insights Ahead

      August 27, 2025

      Navigating the Complex Landscape of Finance and Fintech Marketing

      August 27, 2025
    • Legal & Compliance

      Exploring Thought Leadership’s Impact on Legal Marketing

      August 27, 2025

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Why Transparency Matters in Legal Advertising Practices

      August 27, 2025
    • Medical Marketing

      Enhancing Online Reputation Management in Hospitals: A Guide

      August 27, 2025

      Analyzing Emerging Trends in Health and Medical Marketing

      August 27, 2025

      Exploring Innovative Content Ideas for Wellness Blogs and Clinics

      August 27, 2025
    • E-commerce & Retail

      Strategic Seasonal Campaign Concepts for Online and Retail Markets

      August 27, 2025

      Emerging Trends in E-commerce and Retail Marketing Strategies

      August 27, 2025

      Maximizing Revenue: The Advantages of Affiliate Marketing for E-Commerce

      August 27, 2025
    • Influencer & Community

      Leveraging Influencers: Key Drivers in New Product Launches

      August 27, 2025

      Top Influencer Marketing Platforms to Explore in 2025

      August 27, 2025

      Key Strategies for Successful Influencer Partnership Negotiations

      August 27, 2025
    • Content & Leadership

      The Impact of Social Proof on Thought Leadership Marketing

      August 27, 2025

      Balancing Value-Driven Content and Promotional Messaging Strategies

      August 27, 2025

      Analyzing Storytelling’s Impact on Content Marketing Effectiveness

      August 27, 2025
    • SEO & Analytics

      Scaling Success: Monitoring Indexation of Programmatic SEO Content

      August 27, 2025

      Strategies to Mitigate Duplicate Content in Programmatic SEO

      August 27, 2025

      Effective Data Visualization Techniques for SEO Reporting

      August 27, 2025
    • Marketing Trends

      How Privacy-First Marketing Will Transform the Industry Landscape

      August 27, 2025

      Emerging Trends in Marketing Automation and AI Tools for 2023

      August 27, 2025

      Maximizing ROI: Key Trends in Paid Social Advertising

      August 27, 2025
    Soshace Digital Blog
    Blog / JavaScript / Node.js / Express.js / Securing Node.js Applications with JWT and Passport.js
    Express.js

    Securing Node.js Applications with JWT and Passport.js

    EkekentaBy EkekentaMay 2, 2023Updated:May 2, 2023No Comments11 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    Securing Node.js Applications with JWT and Passport.js
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link
    Securing Node.js Applications with JWT and Passport.js
    Securing Node.js Applications with JWT and Passport.js

    In this tutorial, I’ll share with you how to secure your Node.js applications using JSON Web Tokens (JWT) and Passport.js. We’ll build a sample app together, and I’ll walk you through each step, explaining the code snippets along the way.

    Prerequisites

    Before getting started with this tutorial, ensure you have the following installed on your computer:

    • Node.js and npm
    • A code editor like  Visual Studio Code

    Also, the code for this tutorial is available here on my Github account, feel free to clone it to follow along.

    Introduction to JWT

    JSON Web Tokens (JWT) is a compact and self-contained technique for securely transferring data between parties as a JSON object is defined by the open standard. They are useful for authorization and authentication. They are useful for authorization and authentication.

    JWTs are frequently used in web application authentication and authorization. When a user logs into a web application, the server can generate a JWT with the user’s information (such as their username or user ID) and sign it with a secret key. This signed JWT is then returned to the client as a response to the login request, and the client can use it to verify their identity and access protected resources in subsequent server requests.

    JWTs are designed to be self-contained and tamper-proof, which means that the data contained within the token can be trusted and verified without the need for a separate server-side state. JWTs can also include an expiration date after which the token is no longer valid, which aids in the prevention of token misuse and unauthorized access.

    What is Passport.js

    Passport.js is an authentication middleware for Node.js. It is designed to be extremely adaptable and modular, allowing developers to easily integrate various authentication strategies into their applications.

    Passport.js accepts various authentication methods, including username and password, social media logins (such as Facebook and Twitter), JSON Web Tokens (JWTs), and others. Each strategy is implemented as a separate module, which allows developers to mix and match strategies as needed.

    Passport.js is based on a set of middleware functions that handle authentication and authorization in a standardized manner. These middleware functions, which provide fine-grained authentication control, can be added to individual routes or applied to the entire application.

    Setting up the Project

    Let’s get started by making a new directory for our project and launching a new Node.js application:

    mkdir jwt-passport-demo
    cd jwt-passport-demo
    npm init -y

    Now, we need to install the required dependencies:

    npm install express jsonwebtoken passport passport-jwt bcryptjs
    

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

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      res.send('Hello, World!');
    });
    
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`Server running on port ${PORT}`);
    });
    

    In the above code snippet, I imported the express library and created an instance of an Express app. Then I defined a root route handler that sends a ‘Hello, World!‘ message when the route is requested, setting a variable PORT to the value of the environment variable process.env.PORT if it exists, or to the value 3000 if it does not exist, and started the server listening on the specified port using app.listen().

    How It works

    Before I dive into implementing JWT in our Express Application, quickly look at the diagram below to get an overview of how JWT Authentication works.

    Diagram of how JWT Authentication works
    Diagram of how JWT Authentication works

    Implementing JWT Authentication

    I’ll start by implementing user registration and login routes. To do this, I’ll create a user array to act as a simple in-memory database.

    First, create a new folder named routes and add a file named auth.js. This file will contain our authentication routes.

    Next, add the following code to auth.js:

    const express = require('express');
    const jwt = require('jsonwebtoken');
    const bcrypt = require('bcryptjs');
    const router = express.Router();
    
    const users = [];
    
    module.exports = { router, users };
    

    In the above code snippet, I imported the jwt and bcrypt modules. The JWT module will allow you to sign and verify users’ tokens, while the bcrypt allows you to add an extra layer of protection to your user’s password by creating a hashed version of the password before saving it. Then I created a variable to store the user’s details since I don’t have a database setup for this tutorial.

    Read More:  Handling GraphQL API Authentication using Auth0 with Hasura Actions

    Now let’s create the /register route and use bcryptjs to hash the user’s password:

    router.post("/register", async (req, res) => {
      try {
        const { username, password } = req.body;
    
        const hashedPassword = await bcrypt.hash(password, 10);
        const newUser = { username, password: hashedPassword };
        users.push(newUser);
    
        res
          .status(201)
          .json({ message: "User registered successfully", user: newUser });
      } catch (e) {
        console.log(e.message);
      }
    });

    Next, let’s implement the /login route. We’ll compare the provided password with the stored hashed password and, if successful, generate a JWT:

    router.post("/login", async (req, res) => {
      try {
        const { username, password } = req.body;
    
        const user = users.find((u) => u.username === username);
    
        if (!user) {
          return res.status(400).json({ message: "Invalid username or password" });
        }
    
        const passwordMatch = await bcrypt.compare(password, user.password);
    
        if (!passwordMatch) {
          return res.status(400).json({ message: "Invalid username or password" });
        }
    
        const token = jwt.sign(
          { username: user.username },
          process.env.JWT_SECRET,
          {
            expiresIn: "1h",
          }
        );
    
        res.json({ message: "Logged in successfully", token });
      } catch (e) {
        console.log(e.message);
      }
    });

    In the above code, I created a route handler for the /login path using the HTTP POST method. The route handler accepts a username and password from the request body, searches for a user with the specified username in an array of users, and checks if the password matches the user’s password. If the login is successful, a JWT is generated and returned to the client in the response

    Now, let’s import the auth routes into app.js and add a middleware route for the authRoutes:

    ...
    const { router } = require("./routes/auth");
    ...
    
    app.use(express.json());
    app.use('/auth', router);
    
    ...

    Securing Routes with Passport.js

    Now that you have the authentication routes, let’s secure some routes using Passport.js and JWT.

    First, create a new file named passport-config.js in the root directory. This file will contain our Passport.js configuration. Add the following code to passport-config.js:

    const JwtStrategy = require('passport-jwt').Strategy;
    const ExtractJwt = require('passport-jwt').ExtractJwt;
    
    const users = require('./routes/auth').users;
    
    const opts = {
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: process.env.JWT_SECRET
    };
    
    module.exports = passport => {
      passport.use(
        new JwtStrategy(opts, (jwt_payload, done) => {
          const user = users.find(u => u.username === jwt_payload.username);
    
          if (user) {
            return done(null, user);
          }
    
          return done(null, false);
        })
      );
    };
    

    This code exports a function that configures a Passport.js JWT authentication strategy using the passport-jwt library. In the function, I defined an options object that specifies how to extract the JWT from the request, and the secret key used to sign the JWT. Then I created a new JwtStrategy object and sets up a callback function to be called when the JWT is verified. Finally, I exported the Passport.js middleware.

    To keep your JWT secret key safe, create a .env file in the root directory of the project and add the credential for your JWT secret.

    JWT_SECRET = SLEPe87w7eEue337ehndn3hHDjjKKDK

    You can use run the command below on your terminal to generate a more secure secret for your application.

    node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"

    Then install the dotenv package to load the environment variables from your .env file:

    npm install dotenv

    Open the app.js file and import the dotenv package with code below:

    ...
    require('dotenv').config();
    ...

    Now, let’s import and initialize Passport.js in our app.js:

    ...
    const passport = require('passport');
    require('./passport-config')(passport);
    
    ...
    
    app.use(passport.initialize());
    

    Finally, let’s create a protected route that requires a user to have a valid JWT token to access:

    app.get('/protected', passport.authenticate('jwt', { session: false }), (req, res) => {
      res.send('You have accessed a protected route!');
    });
    

    Implementing refresh tokens

    To enhance the security of a web application that uses JWT for authentication, it is also important to implement a JWT refresh token.  In the login route, I will generate a refresh token along with the access token, and store it in the user object:

    const crypto = require('crypto');
    //...
    
    const refreshToken = crypto.randomBytes(64).toString('hex');
    user.refreshToken = refreshToken;
    
    
    //...
    
    res.json({ message: "Logged in successfully", token, refreshToken });

    Next, create an endpoint for exchanging refresh tokens:

    router.post("/token", (req, res) => {
      const { refreshToken } = req.body;
      const user = users.find((u) => u.refreshToken === refreshToken);
      if (!user) {
        return res.status(403).json({ message: "Invalid refresh token" });
      }
      //...
    });

    Generating new access tokens using refresh tokens

    Now that we have implemented refresh tokens and stored them securely, let’s move on to the next step, which is using them to generate new access tokens. When the access token has expired, the client will use the refresh token to obtain a new access token instead of asking the user to log in again. This process is transparent to the user and allows them to use the application seamlessly without having to provide their login credentials repeatedly. Let’s see how we can implement it. In the /token endpoint, generate a new access token using the user’s refreshToken:

    // ...
      const newToken = jwt.sign(
        { username: user.username },
        process.env.JWT_SECRET,
        { expiresIn: "1h" }
      );
      res.json({ message: "New access token generated", token: newToken });

    Token revocation

    Now that we have implemented refresh tokens and the ability to generate new access tokens, let’s take a look at how to handle token revocation. This is an important security feature that allows users to log out of their session or revoke access to their account in the case of a security incident. Create a logout endpoint and clear the refreshToken from the user object:

    router.post("/logout", (req, res) => {
      const { refreshToken } = req.body;
      const user = users.find((u) => u.refreshToken === refreshToken);
      if (!user) {
        return res.status(400).json({ message: "Invalid refresh token" });
      }
      user.refreshToken = null;
      res.json({ message: "User logged out successfully" });
    });

    Best Practices for JWT and Passport.js

    • Secure token storage on the client-side: Store tokens securely in the client, preferably using HttpOnly cookies or the localStorage or sessionStorage APIs.
    • Handling token expiration and renewal: Monitor token expiration on the client-side and request a new token using the refreshToken before the current token expires.
    • Monitoring and logging authentication events: Use logging and monitoring tools like Winston, Loggly, or Sentry to track user authentication events for audit and troubleshooting purposes.
    • Regularly updating dependencies and security patches: Keep your dependencies updated using tools like npm audit or Dependabot, and apply security patches as needed to keep your application secure.
    Read More:  React Lesson 11. Pt.2: Redux Middlewares

    Testing the Application

    To test our application, we can use tools like Postman or cURL to send HTTP requests. For this demonstration, I will use cURL to test the application. Register a new user by sending a POST request  http://localhost:3000/auth/register with a JSON payload containing a username and password.

    curl -X POST -H "Content-Type: application/json" -d '{"username":"clinton","password":"12345gor"}' http://localhost:3000/auth/register
    
    Message: "User registered successfully"
    Message: “User registered successfully”

    Next, log in with the new user by sending a POST request to http://localhost:3000/auth/login with the same JSON payload.

    curl -X POST -H "Content-Type: application/json" -d '{"username":"clinton","password":"12345gor"}' http://localhost:3000/auth/register
    Message: "Logged in successfully"
    Message: “Logged in successfully”

    Lastly, copy the JWT returned in the response, and use it as a Bearer token to access the protected route at http://localhost:3000/protected.

    curl -X GET -H "Authorization: Bearer your_token_here" http://localhost:3000/protected
    You have accessed a protected route
    You have accessed a protected route

    Replace your_token_here with an actual authorization token that you have obtained through a successful authentication process with your web service. The -H option sets the Authorization header in the request to the specified token.

    If the token is valid and the user is authorized to access the protected resource, the server will respond with the requested resource (You have accessed a protected route!). If the token is invalid or the user is not authorized, the server will return a 401 Unauthorized error response. You can go ahead to test other endpoints like the /auth/tokens and /auth/logout endpoints.

    Conclusion

    Congratulations! You’ve successfully secured a Node.js application using JWT and Passport.js. You can now adapt this tutorial to fit the needs of your own applications. Remember to always keep your JWT secret secure and never store sensitive information in the JWT payload. Happy coding!

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Ekekenta

      Related Posts

      Streamlining Resource Allocation for Enhanced Project Success

      December 18, 2024

      Conducting Effective Post-Project Evaluations: A Guide

      December 16, 2024

      Strategies for Keeping Projects on Track and Meeting Deadlines

      December 10, 2024
      Leave A Reply Cancel Reply

      You must be logged in to post a comment.

      Stay In Touch
      • Facebook
      • Twitter
      • Pinterest
      • Instagram
      • YouTube
      • Vimeo
      Don't Miss
      Interview March 22, 2019

      How to Take Control of Your Tech Interview | Take Charge in Three Easy Steps

      We explore some of the most subtle techniques that we’ll help you take control of the interview process. Land this tech job now by following these three easy steps.

      23. Уроки Node.js. Домены, “асинхронный try..catch”. Часть 1.

      November 14, 2016

      Node.js Lesson 6: Util and Inheritance

      October 2, 2020

      21. Уроки Node.js. Writable Поток Ответа res, Метод pipe. Pt.2

      October 26, 2016

      Categories

      • AI & Automation
      • Angular
      • ASP.NET
      • AWS
      • B2B Leads
      • Beginners
      • Blogs
      • Business Growth
      • Case Studies
      • Comics
      • Consultation
      • Content & Leadership
      • CSS
      • Development
      • Django
      • E-commerce & Retail
      • Entrepreneurs
      • Entrepreneurship
      • Events
      • Express.js
      • Facebook Ads
      • Finance & Fintech
      • Flask
      • Flutter
      • Franchising
      • Funnel Strategy
      • Git
      • GraphQL
      • Home Services Marketing
      • Influencer & Community
      • Interview
      • Java
      • Java Spring
      • JavaScript
      • Job
      • Laravel
      • Lead Generation
      • Legal & Compliance
      • LinkedIn
      • Machine Learning
      • Marketing Trends
      • Medical Marketing
      • MSP Lead Generation
      • MSP Marketing
      • NestJS
      • Next.js
      • Node.js
      • Node.js Lessons
      • Paid Advertising
      • PHP
      • Podcasts
      • POS Tutorial
      • Programming
      • Programming
      • Python
      • React
      • React Lessons
      • React Native
      • React Native Lessons
      • Recruitment
      • Remote Job
      • SaaS & Tech
      • SEO & Analytics
      • Soshace
      • Startups
      • Swarm Intelligence
      • Tips
      • Trends
      • Vue
      • Wiki
      • WordPress
      Top Posts

      Creating Real-Time API with Beautiful Soup and Django REST Framework

      Python February 26, 2020

      The Best Work Tools for Remote Teams — Part 2: Team Communication

      Job May 3, 2019

      Interview With Oleg – Soshace Team

      Interview December 8, 2016

      Unlock B2B Leads: Harnessing Strategic Partnerships Effectively

      B2B Leads November 24, 2024

      Subscribe to Updates

      Get The Latest News, Updates, And Amazing Offers

      About Us
      About Us

      Soshace Digital delivers comprehensive web design and development solutions tailored to your business objectives. Your website will be meticulously designed and developed by our team of seasoned professionals, who combine creative expertise with technical excellence to transform your vision into a high-impact, user-centric digital experience that elevates your brand and drives measurable results.

      7901 4th St N, Suite 28690
      Saint Petersburg, FL 33702-4305
      Phone: 1(877)SOSHACE

      Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
      Our Picks
      JavaScript

      This Is How I Created a Simple App Using React Routing

      Programming

      1. Уроки Node.js .Модули. Часть 1.

      JavaScript

      React Lesson 13 Part 2: Asynchronous actions

      Most Popular

      Unlock B2B Leads: Harnessing Strategic Partnerships Effectively

      B2B Leads

      A Guide to HR Developing Performance Goals

      Franchising

      Balancing Value-Driven Content and Promotional Messaging Strategies

      Content & Leadership
      © 2025 Soshace Digital.
      • Home
      • About
      • Services
      • Contact Us
      • Privacy Policy
      • Terms & Conditions

      Type above and press Enter to search. Press Esc to cancel.