DEV Community

Lakhan Samani
Lakhan Samani

Posted on

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 provider One-click link Additional information
Railway.app Deploy on Railway docs
Heroku Deploy to Heroku docs
Render render button docs

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

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.

Top comments (1)

Collapse
 
teaganga profile image
teaganga

Nice, I was also checking different ways to secure an api, but without using specialized libraries: Securing a Node.js API: A Simple Guide to Authentication. I using a specialized library, if it's well maintained, is beneficial