Node.js Unleashed: Supercharge Your Web App with Rock-Solid Authentication and Authorization!

Node.js Unleashed: Supercharge Your Web App with Rock-Solid Authentication and Authorization!

ยท

9 min read

Introduction

Hello there๐Ÿ‘‹๐Ÿผ, Welcome to my tech blog, today we will be discussing handling authentication and authorization in Node.js using JSON Web Token (JWT).

Now we know what we are up to, let's get started๐Ÿš€

Prerequisite

  • Nodejs (Express)

What is Authentication and Authorization?

Authentication: The idea behind authentication is just the process of proving your identity, to get access. Let's consider a scenario where you have been selected at random by username as the lucky winner of a million dollars by Mark Zuckerberg (CEO of Instagram). The process of proving you are sincerely the one who owns the username- the screenshots, the files, the receipts you bring out in other not to lose that life-changing opportunity๐Ÿ˜… is what is referred to as AUTHENTICATION.

An Authentication is successful when your identity has been confirmed or in more technical terms when you have been confirmed to have authorized access.

Authorization: Continuing with our story, authorization is what dictates the permission we have after receiving access. In our scenario, it would be Mark Zuckerberg letting us know what we can do with our newfound wealth๐Ÿ’ฐ- whether we can withdraw funds, invest, only spend within Instagram or just view our account balance (I hope not๐Ÿ˜‚).

The process of specifying these terms is referred to as AUTHORIZATION.

What is JWT?

JWT is an acronym for JSON Web Token, It is a way of passing information securely. JWTs are divided into three parts, Firstly is the header which contains the algorithm used in signing the token and the type of token, Secondly, there is a payload- which contains the information or data we are trying to keep secured and Lastly is the signature which ensures the integrity and authenticity of the token

Authentication in Node.Js

As we described authentication earlier, it's the process of proving who you are, your identity can't be confirmed if there wasn't an identity requirement to be met. In most cases, this requirement is gotten during a sign-up process and requested during login. After signing up successfully, the user data is sent to the server and stored in a database, so the authentication process during login ensures the input matches the data in the database.

As we move further we will be using email and password as the credentials required to login.

First and foremost we need to open our IDE and create a new folder for our project, Let's name it auth-with-jwt.

I will be creating from my terminal:

mkdir auth-with-jwt

Next, we navigate to our newly created folder:

cd auth-with-jwt

Then we initialize Node.js in our folder:

npm init --y

In this article, we will be working with express.js. Let's proceed by installing our necessary packages

npm install express jsonwebtoken body-parser

express: This is a Node.js framework that would make our coding process faster and more organized.

jsonwebtoken: This package is what will we use to generate our token and verify it as discussed earlier in this article.

body-parser: This package helps to parse body requests, that is, it helps to receive data sent from the client into the server.

Next, we create our base file- index.js, import all packages and create the server. It should look like this:


const express = require("express");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");

const app = express();
const port = 3000; // port to listen on
app.use(bodyParser.json());

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

As I said earlier we need data to cross-check with, To determine if the data given is valid. Since we don't have a database we are working with let's create an array of dummy data we would use throughout this article


const express = require("express");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");

const app = express();
const port = 3000; // port to listen on
app.use(bodyParser.json());

// Dummy user data for authentication
const users = [
  { id: 1, username: "user1", password: "password1" },
  { id: 2, username: "user2", password: "password2" }
];

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

The next step is creating the login endpoint, where we receive data from the users and check if it matches what we have in our dummy data. As I said earlier in this article, authentication is simply proving who you are, therefore the process of receiving data and checking its validity is known as AUTHENTICATION.

Authentication is successful if the data matches what we have in the database or this case our dummy data. Once authentication is successful we then have authorized access and if not successful we have unauthorized access with a status code of 401. where we can return a response that explains no user exists with such credentials.


const express = require("express");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");

const app = express();
const port = 3000; // port to listen on
app.use(bodyParser.json());

// Dummy user data for authentication
const users = [
  { id: 1, username: "user1", password: "password1" },
  { id: 2, username: "user2", password: "password2" }
];
// Login route to generate and send a JWT upon successful authentication
app.post("/login", (req, res) => {
  const { username, password } = req.body; //represent data sent to client
  //Authentication 
  const user = users.find(
    (u) => u.username === username && u.password === password
  );
  if (!user) {
    return res.sendStatus(401); // Unauthorize Access
  }
});
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Next, we will need to handle the next step for an authorized user, i.e. creating a token and signing it.

There is a jsonwebtoken method for that it's called the sign method sign(). This method takes two parameters.

Firstly, there is an object, which is referred to as the PAYLOAD- It consists of the protected data mostly the data you plan on accessing on the protected page.

Secondly, there is a string called the SECRET KEY or SIGNATURE- This is a unique key that helps us ensure the authenticity of our token. It can be seen as a password we set, so others can't gain access without knowledge of the password.


const express = require("express");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");

const app = express();
const port = 3000; // port to listen on
app.use(bodyParser.json());
const secretKey = "YOUR_SECRET_KEY"
// Dummy user data for authentication
const users = [
  { id: 1, username: "user1", password: "password1" },
  { id: 2, username: "user2", password: "password2" }
];
// Login route to generate and send a JWT upon successful authentication
app.post("/login", (req, res) => {
  const { username, password } = req.body; //represents data sent from client
  //Authentication
  const user = users.find(
    (u) => u.username === username && u.password === password;
  );
  if (!user) {
    return res.status(401).json({success:false, message:"Email does not match password"}); // Unauthorize Access
  }
   //Generate Token
  const token = jwt.sign({ id: user.id, username: user.username }, secretKey);
  res.json({success:true,  token }); //Send Token
});
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Authorization

As we said earlier, Authorization is simply giving access to a route after a successful authentication.

To explain we will need

  • A protected route, let's call it profile.

  • A middleware function to give access to the protected route- /profile, let's call our middleware verifyToken().

Starting with the verifyToken middleware, in this function we confirm if the token is correct with a jwt method called verify(). This method receives three parameters namely:

  • Token: This is the token we are trying to verify it's authenticity.

  • Secret key: The password to the authentication as discussed above. This must be the same as the key used in authentication.

  • Options: This is a temporary parameter, It can be a function, this is mostly used if there is specific data to return**.**

// Middleware to verify JWT token and protect routes
function verifyToken(req, res, next) {
 // Receiving the token from the header
  const token = req.headers['authorization'];

  if (!token) {
    return res.status(401).json({message:"Unauthorized"}); // Unauthorized
  }
// Token Verification
  jwt.verify(token, secretKey, (err, user) => {
    if (err) {
      return res.status(403).json({message:"Invalid Token"}); // Forbidden (invalid token)
    }
    req.user = user; // Adding the user to the req on successful token verification 
    next(); // Moving to the next function only after successful verification
  });
}

The Protected Route (/profile): Since we only want access to this route after successful token verification we call the function only after we call the verifyToken middleware.

// Middleware to verify JWT token and protect routes
function verifyToken(req, res, next) {
 // Receiving the token from the header
  const token = req.headers['authorization'];

  if (!token) {
    return res.status(401).json({message:"Unauthorized"}); // Unauthorized
  }
// Token Verification
  jwt.verify(token, secretKey, (err, user) => {
    if (err) {
      return res.status(403).json({message:"Invalid Token"}); // Forbidden (invalid token)
    }
    req.user = user; // Adding the user to the req on successful token verification 
    next(); // Moving to the next function only after successful verification
  });
}
//Protected Route
app.get("/profile", verifyToken, (req,res)={
    res.json({ message: 'You have access to this protected resource!', user: req.user });
})

All put together your file should be like this:


const express = require("express");
const jwt = require("jsonwebtoken");
const bodyParser = require("body-parser");

const app = express();
const port = 3000; // port to listen on
app.use(bodyParser.json());
const secretKey = "YOUR_SECRET_KEY"
// Dummy user data for authentication
const users = [
  { id: 1, username: "user1", password: "password1" },
  { id: 2, username: "user2", password: "password2" }
];
// Middleware to verify JWT token and protect routes
function verifyToken(req, res, next) {
 // Receiving the token from the header
  const token = req.headers['authorization'];

  if (!token) {
    return res.status(401).json({message:"Unauthorized"}); // Unauthorized
  }
// Token Verification
  jwt.verify(token, secretKey, (err, user) => {
    if (err) {
      return res.status(403).json({message:"Invalid Token"}); // Forbidden (invalid token)
    }
    req.user = user; // Adding the user to the req on successful token verification 
    next(); // Moving to the next function only after successful verification
  });
}
// Login route to generate and send a JWT upon successful authentication
app.post("/login", (req, res) => {
  const { username, password } = req.body; //represents data sent from client
  //Authentication
  const user = users.find(
    (u) => u.username === username && u.password === password;
  );
  if (!user) {
    return res.status(401).json({success:false, message:"Email does not match password"}); // Unauthorize Access
  }
   //Generate Token
  const token = jwt.sign({ id: user.id, username: user.username }, secretKey);
  res.json({success:true,  token }); //Send Token
});
//Protected Route
app.get("/profile", verifyToken, (req,res)={
    res.json({ message: 'You have access to this protected resource!', user: req.user });
})
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Awesome! ๐Ÿ˜„ We've just nailed down how authentication and authorization roll in Node.js. Big congrats to you! ๐ŸŽ‰

Wrap-up

In a nutshell, authentication and authorization brings privacy to your web application. authentication is simply the process of identifying a user and authorization is granting users access to specific routes. We use a tool called JSON Web Token (JWT) to generate a token, which is just a string with random characters along with a signature to authenticate in our web app. NOTE: Your secret key should be hidden in an environmental variable (env), to provide the best safety and security of your web app.

If you found this article enjoyable, please give it a thumbs-up ๐Ÿ‘ and share your thoughts in the comments below ๐Ÿ’ฌ. Stay tuned for even more thrilling tech content by subscribing to my newsletter! ๐Ÿ“ฉ๐Ÿš€๐Ÿ˜Š

See you soon ๐Ÿ˜‰

ย