So this is the part 2 of the User Authentication with NodeJS. You can check out the Part - 1 here. In this Part we talk about the modern solution for User Authentication which is much more feasible and scalable. Token Based Authentication.
Token Based Authentication
In token based authentication, when a user logins with correct credentials a token (a long string with random characters and numbers) is generated and sent back to the client's browser where it is stored (in localStorage, SessionStorage or cookie). Now every time a user will make a request to the server that token stored in browser will be sent back to the server and we will have some middleware function to verify the token and give back the required resources.
Let's implement it in code.
Create an empty NodeJS project and in terminal run the command
npm install express jsonwebtoken mongoose
express - For creating our server
mongoose - To Connect to our MongoDB Database
jsonwebtoken - Known as JWT, it is an open source npm package for generating access tokens securely
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');
await mongoose.connect('your_mongo_url', (err, db) => {
console.log('MongoDB Connected....');
});
app.get('/', (req,res)=>{
res.send('<h1>Hello World!</h1>');
})
app.listen(5000, () => console.log(`Server π₯π₯π₯ up on 5000`));
This block of code will make our server up and running on Port 5000. So if you now visit http://localhost:5000/ you will see the desired result.
app.post("/login", async (req, res) => {
try {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) {
return res.json({ msg: "Please enter a valid username" });
}
const accessToken = jwt.sign(
{ username, id: user._id },
JWT_SECRET,
{
expiresIn: process.env.NODE_ENV === "production" ? "6h" : "2 days",
}
);
res.json({ msg: "User logged in!", accessToken });
} catch (err) {
console.log(err);
res.status(503).json({ msg: "Server error!" });
}
});
So above block of code is posting the login credentials and logging in the user. Let us understand the jwt.sign()
functionality which is creating our access token.
JWT - Json Web Token has a method called sign()
which is used to create a new web token which will contain user information in a hidden way. There are three parameters in jwt.sign()
method. Let's talk about each of them.
First is the data to be stored in the token. It can be a string or a javascript object. In this example we stored username and id (mongodb unique generated id) in the access token.
Second parameter is the
JWT_SECRET
. It can be anything (a random string) and it is important not to display it in production. You should use environment variables for saving the JWT_SECRET. It'll be used later on to verify the JWT Token and authenticate the user.Third parameter is optional properties that can be defined for the access token, like expiry date, httpOnly etc. You can check out more in detail about the optional parameters here
This function will return us a string of random characters which is called a jwt access token. Something like this:
eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjYwZndmNzA5N2ZmN2YwOTdmMDk5IiwidXNlcm5hbWUiOiJsYXZpc2hnb3lhbCJ9.kNPmoyim0KbrHw6Fl2NPdUWO3UdZ1cr3rFH4eZy9DIg
Now if you how this token contains information about user, open another tab in your browser and go to https://jwt.io/ and in the encoded input box paste the above access token and you'll receive the id and username as shown below
If you look closely there are two dots in the JWT Access token which divides the token string into three parts.
The first part is the algorithm for encoding the token, second part consists the user details we entered and third part is the JWT Secret used to verify the user later (which we'll do just now)
const authenticateToken = (req, res, next) => {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
if (token === null) return res.status(401).json({ msg: "Not Authorized" });
jwt.verify(token, JWT_SECRET, (err, user) => {
if (err) return res.status(401).json({ msg: err });
req.user = user;
next();
});
};
This block of code will verify the incoming JWT token and authenticate the user and we can proceed with further data processing. jwt.verify()
takes in three parameters, first is the token which we'll receive from client. The token can be received either via cookie or in headers. Here the token is passed in the header Authorization
Header. *Remember the JWT_SECRET should be the same among the whole project otherwise the jwt token will not be decoded and return an error of invalid token. *
Now the above authenticateToken middleware function can be used in all the protected routes to verify if the user is eligible for accessing data at that particular route for example:
app.get("/dashboard", authenticateToken, (req,res)=>{
res.send('<h1>Welcome to dashboard</h1>')
})
So in the above code we used the authenticateToken as the middleware function and if the client's request contains a correct jwt token user will be shown Welcome to dashboard heading otherwise will be shown an error.
That was all folks. That was all about the authentication and authorization with NodeJS. There are much more complex and secure ways to do authentication but it was a beginner's tutorial so I kept it that way. Will cover more about it in next blogs. Until then share the post and tag me on twitter.
See Ya!
Top comments (1)
i would really appreciate for once if you can do this entire series in postgres instead of mongoose