Authorize NodeJS APIs using Authorizer

In this blog post, we will learn how to authorize users for API calls, based on valid sessions and roles using Authorizer. Authorizer is an open-source database-independent auth solution. You can bring your database and have authentication and authorization service ready out of the box.

For the demo purpose, we will be using [Express](https://expressjs.com/) server and writing a middleware that will validate user sessions & roles based on the JWT (JSON Web Token) in the Authorization header.

Refer to the source code on github.

Step 1: Setup Authorizer Instance

Deploy production-ready Authorizer instance using one-click deployment options available below

Infra providerOne-click linkAdditional information
Railway.appDeploy nowdocs
HerokuDeploy nowdocs
RenderDeploy nowdocs

For more information & deployment options like docker / Kubernetes / helm charts refer to the docs

Configure Instance

  • Open the Authorizer instance endpoint in a browser

  • SignUp as an Admin with a secure password

  • Configure environment variables from the dashboard. Check env docs for more information.

    Note: DATABASE_URL , DATABASE_TYPE , REDIS_URL are the variables that can only be configured as the authorizer instance's system environment variable.

Step 2: Create Express App

Note: This step is optional if you already have a Nodejs application up and running

  • Setup project

      # Create directory
      mkdir my-apis
    
      # Change directory
      cd my-apis
    
      # Initialize nodejs APP
      npm init -y
    
      # Install express
      npm install express
    
      # Create index.js
      touch index.js
    
  • Add Start Command to package.json

      {
        "name": "my-apis",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "start": "node index.js",
          "test": "echo \"Error: no test specified\" && exit 1"
        },
        "keywords": [],
        "author": "Lakhan Samani",
        "license": "ISC",
        "dependencies": {
          "express": "^4.18.2"
        }
      }
    
  • Setup Express App and Create a basic API in index.js

      // index.js
      const express = require('express');
    
      const app = express();
      const port = `3000`;
    
      app.get('/', (req, res) => {
        res.send('Hello World');
      });
    
      app.listen(port, () => {
        console.log(`[server]: Server is running at http://localhost:${port}`);
      });
    

Step 3: Create Authorization Middleware

  • Install @authorizerdev/authorizer-js

      npm i --save @authorizerdev/authorizer-js
    
  • Create auth_middleware.js

      touch auth_middleware.js
    
  • Implement authorization middleware

      // auth_middleware.js
    
      const { Authorizer } = require("@authorizerdev/authorizer-js");
    
      const authRef = new Authorizer({  
        authorizerURL: "AUTHORIZER_URL_FROM_STEP 1",
        redirectURL: "FRONTEND_URL",
        clientID: "AUTHORIZER_CLIENT_ID FROM DASHBOARD"
      });
    
      const authMiddleware = async (req, res, next) => {
          const authHeader = req.headers.authorization;
        if (!authHeader) {
          return res.status(403).json({ error: "Authorization not found" });
        }
    
        const splitHeader = authHeader.split(" ");
        if (splitHeader.length != 2) {
          return res.status(403).json({ error: "Invalid auth header" });
        }
    
        if (splitHeader[0].toLowerCase() != "bearer") {
          return res.status(403).json({ error: "Bearer token not found" });
        }
    
        const token = splitHeader[1];
        // Validate jwt token via authorizer sdk
        try {
          const res = await authRef.validateJWTToken({
            token,
            token_type: "id_token", // This can be access_token, refresh_token
             // roles: [user] // specify roles that you want to validate jwt for, by default it will just verify jwt.
          });
          req.user = res.claims;
        } catch (err) {
          console.error(err);
          return res.status(403).json({ error: "Invalid JWT token" });
        }
    
        next();
      }
    
      module.exports = authMiddleware
    

Step 4: Add auth middleware to APIs

Update index.js with following content

// index.js
const express = require('express');
const authMiddleware = require('./auth_middleware')

const app = express();
const port = `3000`;

app.get('/', authMiddleware, (req, res) => {
  res.send('Hello World');
});

app.listen(port, () => {
  console.log(`[server]: Server is running at http://localhost:${port}`);
});

Step 5: Test the API

  • Start API Server

      npm start
    
  • Make a curl request

      curl http://localhost:3000
    

Note: This will return an error, as we have not specified the Authorization header with a valid JWT token

  • For this test to pass we need to have a valid JWT token, so let's generate a valid JWT by making a login call to the authorizer server

      # Replace Authorizer URL from step 1
      # Replace credentials with right credentials in --data-raw (demo@yopmail.com, Test@123#)
      # If you have no user on your instance, first signup using AUTHORIZER_URL_FROM_STEP_1/app?redirect_uri=AUTHORIZER_URL_FROM_STEP_1/app
    
      curl --location --request POST 'AUTHORIZER_URL_FROM_STEP_1/graphql' \
      --header 'Content-Type: application/json' \
      --data-raw '{"query":"mutation login {\n  login(params: {\n    email: \"demo@yopmail.com\",\n    password: \"Test@123#\"\n  }) {\n    id_token\n  }\n}","variables":{}}'
    

    This should return an id_token in response, as shown in the screenshot below. Copy the id_token from the response and pass it to our nodeJS API server

  • Test the API

      curl --header 'Authorization: Bearer TOKEN_COPIED_FROM_ABOVE_STEP' http://localhost:3000
    

That's all I hope this helps you authorize your APIs easily and make them secure based on the correct session and roles.

For more information check out the links below.