• Labs icon Lab
  • Core Tech
Labs

Guided: Securing Node.js Microservices with JWT Authentication

This lab will make it easy for you to authenticate NodeJS microservices using JWTs. You’ll learn how easy and straightforward JWT authentication is, and how simple it can be to authorize based on route, token contents, or both.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 42m
Published
Clock icon Mar 15, 2024

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. Challenge

    Introduction

    This Guided Code Lab, Securing Node.js Microservices with JWT Authentication, will give you a clear understanding of how to use JSON Web Tokens (JWTs) to secure a Node.js microservice written using the express HTTP framework. JWTs are transparent tokens that represent authorization from an OAuth2 authorization provider. These tokens carry cryptographic signatures that allow an application to verify the authenticity of the token based on the issuer's public key(s). Put simply, this allows an application to verify that the JWT is valid without making additional API calls to an authorization provider.

    Scenario

    You will be modifying the code of a simple express webserver to accept a JWT bearer token to provide authentication and authorization information.

    You will find two files in the src directory that you will be modifying as a part of this lab:

    • manualServer.js

      You will modify this file in Step 1 to create an insecure implementation of authentication using JWT bearer tokens.

    • server.js

      You will modify this file in Steps 2 and beyond to properly secure the express application using JWT bearer tokens.

    In each of these files, the express application is created by a function that accepts a config parameter. This represents configuration parameters that are often handled using environment variables.

    You will also notice the solution directory. This contains solutions for each step of the lab if you get stuck or would like to compare for reference.

  2. Challenge

    Step 1: Manual JWT Authentication

    In this step, you'll be authenticating your express app by manually decoding a JWT so that you can get familiar with the basics of how JWT authentication works.

    info> Warning: The JWT authentication implementation you build in this step has numerous security problems. This is a learning exercise and is not suitable for production use.

    Now, you will integrate the jsonwebtoken package into your code so that you can validate that the Authorization header of incoming requests contains a valid JWT. If you encounter an invalid JWT, you will respond with HTTP status code 403. You will also incorporate a configuration value that is typically handled via environment variables. Now you will make an authentication decision based on the contents of the JWT. A JWT is essentially a collection of claims with a cryptographic signature. So, you will use the sub claim (short for "subject") to validate that the authorized entity meets some set of expectations. For user authentication, the sub claim may be a user's email address. For service-to-service authentication, it may be a service account identifier.

  3. Challenge

    Step 2: JWT Authentication via Discovery

    Now, you'll use OAuth Discovery to automatically configure how your server verifies JWTs. In the previous step, you manually decoded the JWT using a key passed in via a configuration value. Now, you'll take advantage of how OIDC allows you to obtain configuration information directly from the token issuer; that is, the server that creates and provides tokens for use.

    OAuth providers publish their configuration using a discovery endpoint which contains configuration information including public keys, allowed algorithms, and so on. You will use the express-oauth2-jwt-bearer library to handle these details for you. The two key pieces of information that you need to configure this library are:

    1. The base URL of the issuer. This allows the library to fetch the configuration from the issuer's discovery endpoint.
    2. The audience. Generally, JWTs contain an aud claim (short for "audience") that indicates what resource provider the token is intended to provide access to. By convention, this corresponds to the base URL of the application.
  4. Challenge

    Step 3: Authorizing by Route

    Now, you will enable unauthenticated access to a specific path. This is common for scenarios like documentation. In express, this is easily handled by making proper use of the order that handlers and middleware are registered. For example, consider the following sample code:

    const app = express();
    
    app.get('/unprotected', (req, res) => { /* some handler code */ })
    
    app.use(auth(/* authentication configuration */))
    
    app.get('/protected', (req, res) => { /* some handler code */ })
    

    In the example above, the authentication middleware has no effect on GET requests to /unprotected since it is registered after the handler for it. However, GET requests to /protected will be affected by the auth middleware since the middleware is registered before the handler for that path. Now, you will authorize a specific path based on the contents of the JWT. As you saw earlier, a JWT contains claims, and the information in those claims can be used to make authorization decisions. What you will do now is use a role claim to determine what actions are authorized.

  5. Challenge

    Step 4: Advanced Authorization Scenarios

    Now, you will add logic for a new admin role. This role is allowed to perform POST requests. Additionally, this admin role will be allowed to do everything that the manager role can do.

  6. Challenge

    Congratulations

    Well done! You've finished all of the tasks for this lab. You should now be able to easily add JWT Bearer authentication to your own express applications.

    For further reading, check out the documentation for the express-oauth2-jwt-bearer library:

    https://auth0.github.io/node-oauth2-jwt-bearer/

    You may also want to get familiar with security best practices for express apps:

    https://expressjs.com/en/advanced/best-practice-security.html

    Thanks for completing this lab, and thanks for using Pluralsight!

Developer. Craftsman. Leader. Architect. Mentor. Teacher. Author. Floyd is a veteran software craftsman with broad experience and a passion for teaching.

What's a lab?

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Provided environment for hands-on practice

We will provide the credentials and environment necessary for you to practice right within your browser.

Guided walkthrough

Follow along with the author’s guided walkthrough and build something new in your provided environment!

Did you know?

On average, you retain 75% more of your learning if you get time for practice.