Login App - Create REST API for authentication in Node.js using JWT - Part 2
In this article, we will show you how to create REST API for authentication in Node.js using JWT. As we already discussed the implementation flow of login/authentication functionality in First part of the article so now it's time to move on to the second part of the article to create secure REST API in Node.js.
Checkout more articles on ReactJS/Node.js
- Copy text to the Clipboard in ReactJS
- Image upload in ReactJS
- File Upload in Node.js
- URL Parameters with React Router
- Handle Events in React
We planned to divide this article into three parts.
- Part 1 β Implementation flow
- Part 2 β Create REST API for authentication in Node.js using JWT (You are hereβ¦)
- Part 3 - Create login form in ReactJS using secure REST API
Before you continue, we want you to check out the first part of this article.
Way to create REST API for authentication in Node.js
- Create simple REST API in Node.js
- Install all the required npm packages
- Define the environment variable
- Manage general utility
- Create API for user sign in
- Create API for verify token
- Implement middleware to validate the token
- Output
1. Create simple REST API in Node.js
To begin the implementation, We have to start with simple REST API integration in Node.js. If you don't know about it then refer the following link to create REST API.
We will set up a file structure like the one below.
File Structure - Create REST API for authentication in Node.js using JWT - Clue Mediator
Understanding of the project structure.
- .env β To store the environment variables which we can use in application.
- server.js β It's used to create an express server where we can integrate the API for authentication.
- utils.js β It's used to manage the general utility.
2. Install all the required npm packages
We have to install the following npm packages to create API.
- cors β It's an express middleware for enabling Cross-Origin Resource Sharing requests. Just because of it, We can access the API in different applications.
- body-parser β Node.js request body parsing middleware which parses the incoming request body before your handlers, and make it available under req.body property. In other words, it simplifies the incoming request.
- jsonwebtoken β A JSON web tokens (JWT) is JSON Object which is used to securely transfer information over the web(between two parties). It can be used for an authentication process. We will use this package to create token with the help of user primary data and secret or private key. So when we need it then we can decode it and use the user data to manage application logs.
- dotenv β Dotenv is a zero-dependency module that loads environment variables from a .env file into `process.env`. We will store the JWT secret key in .env file.
Run the following command to install the required dependencies.
npm install cors body-parser jsonwebtoken dotenv --save
After a successful installation, you will need to enable the middleware and use it in the server file to handle the request. Check out the following code of the server.js where we use it.
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const app = express();
const port = process.env.PORT || 4000;
// enable CORS
app.use(cors());
// parse application/json
app.use(bodyParser.json());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// request handlers
app.get('/', (req, res) => {
res.send('Welcome to the Node.js Tutorial! - ' + req.user.name);
});
app.listen(port, () => {
console.log('Server started on: ' + port);
});
3. Define the environment variable
We must have a JWT secret key to manage the token so we need to create a .env file in the project directory. It should look like below.
.env
JWT_SECRET=ABCDEF$123
Now we can use "JWT_SECRET" variable via calling `process.env.JWT_SECRET` from any files. But we have to add `require('dotenv').config();` at the top of the server.js file.
4. Manage general utility
Before we create the API, we have to create two functions as "generateToken" & "getCleanUser" in utils.js file.
- generateToken β In this function, we will return the auth token created using the "jsonwebtoken" package. For that, we need basic user details (like id, name, role, etc) and secret key (mentioned in .env file). Make sure don't use password and other sensitive information in user details to create token.
- getCleanUser β In this function, we will return the basic user information which we can pass it to the user along with the token.
utils.js
// generate token using secret from process.env.JWT_SECRET
var jwt = require('jsonwebtoken');
// generate token and return it
function generateToken(user) {
//1. Don't use password and other sensitive fields
//2. Use the information that are useful in other parts
if (!user) return null;
var u = {
userId: user.userId,
name: user.name,
username: user.username,
isAdmin: user.isAdmin
};
return jwt.sign(u, process.env.JWT_SECRET, {
expiresIn: 60 * 60 * 24 // expires in 24 hours
});
}
// return basic user details
function getCleanUser(user) {
if (!user) return null;
return {
userId: user.userId,
name: user.name,
username: user.username,
isAdmin: user.isAdmin
};
}
module.exports = {
generateToken,
getCleanUser
}
5. Create API for user sign in
Here, we can consider the static data to validate the user therefore we will declare user information in the variable of the server file.
// static user details
const userData = {
userId: "789789",
password: "123456",
name: "Clue Mediator",
username: "cluemediator",
isAdmin: true
};
Letβs start creating the API where the user can get authenticated bypassing the login credentials. If the user gets authenticated successfully then we will create a token and return it back.
// validate the user credentials
app.post('/users/signin', function (req, res) {
const user = req.body.username;
const pwd = req.body.password;
// return 400 status if username/password is not exist
if (!user || !pwd) {
return res.status(400).json({
error: true,
message: "Username or Password is required."
});
}
// return 401 status if the credential is not match.
if (user !== userData.username || pwd !== userData.password) {
return res.status(401).json({
error: true,
message: "Username or Password is wrong."
});
}
// generate token
const token = utils.generateToken(userData);
// get basic user details
const userObj = utils.getCleanUser(userData);
// return the token along with user details
return res.json({ user: userObj, token });
});
6. Create API for verify token
Now let's create another API where we can verify the token and based on the given response we can manage the routes in React Application. If token is invalid then we will send "401 Unauthorized" response to the user.
// verify the token and return it if it's valid
app.get('/verifyToken', function (req, res) {
// check header or url parameters or post parameters for token
var token = req.query.token;
if (!token) {
return res.status(400).json({
error: true,
message: "Token is required."
});
}
// check token that was passed by decoding token using secret
jwt.verify(token, process.env.JWT_SECRET, function (err, user) {
if (err) return res.status(401).json({
error: true,
message: "Invalid token."
});
// return 401 status if the userId does not match.
if (user.userId !== userData.userId) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
}
// get basic user details
var userObj = utils.getCleanUser(userData);
return res.json({ user: userObj, token });
});
});
7. Implement middleware to validate the token
At last we need to implement the middleware so we can verify the token for private routes. If token is not exist in the header of the request then we can directly pass the request to the next route and if it's exist then we will verify it and append the user object to the same request and pass it to the next route so in the next route we can use the user object.
//middleware that checks if JWT token exists and verifies it if it does exist.
//In all future routes, this helps to know if the request is authenticated or not.
app.use(function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['authorization'];
if (!token) return next(); //if no token, continue
token = token.replace('Bearer ', '');
jwt.verify(token, process.env.JWT_SECRET, function (err, user) {
if (err) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
} else {
req.user = user; //set the user to req so other routes can use it
next();
}
});
});
// request handlers
app.get('/', (req, res) => {
if (!req.user) return res.status(401).json({ success: false, message: 'Invalid user to access it.' });
res.send('Welcome to the Node.js Tutorial! - ' + req.user.name);
});
Basically this helps to know if the request is authenticated or not.
8. Output
At the end of the development, your server.js file should look like below.
server.js
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const utils = require('./utils');
const app = express();
const port = process.env.PORT || 4000;
// static user details
const userData = {
userId: "789789",
password: "123456",
name: "Clue Mediator",
username: "cluemediator",
isAdmin: true
};
// enable CORS
app.use(cors());
// parse application/json
app.use(bodyParser.json());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
//middleware that checks if JWT token exists and verifies it if it does exist.
//In all future routes, this helps to know if the request is authenticated or not.
app.use(function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['authorization'];
if (!token) return next(); //if no token, continue
token = token.replace('Bearer ', '');
jwt.verify(token, process.env.JWT_SECRET, function (err, user) {
if (err) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
} else {
req.user = user; //set the user to req so other routes can use it
next();
}
});
});
// request handlers
app.get('/', (req, res) => {
if (!req.user) return res.status(401).json({ success: false, message: 'Invalid user to access it.' });
res.send('Welcome to the Node.js Tutorial! - ' + req.user.name);
});
// validate the user credentials
app.post('/users/signin', function (req, res) {
const user = req.body.username;
const pwd = req.body.password;
// return 400 status if username/password is not exist
if (!user || !pwd) {
return res.status(400).json({
error: true,
message: "Username or Password required."
});
}
// return 401 status if the credential is not match.
if (user !== userData.username || pwd !== userData.password) {
return res.status(401).json({
error: true,
message: "Username or Password is Wrong."
});
}
// generate token
const token = utils.generateToken(userData);
// get basic user details
const userObj = utils.getCleanUser(userData);
// return the token along with user details
return res.json({ user: userObj, token });
});
// verify the token and return it if it's valid
app.get('/verifyToken', function (req, res) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token;
if (!token) {
return res.status(400).json({
error: true,
message: "Token is required."
});
}
// check token that was passed by decoding token using secret
jwt.verify(token, process.env.JWT_SECRET, function (err, user) {
if (err) return res.status(401).json({
error: true,
message: "Invalid token."
});
// return 401 status if the userId does not match.
if (user.userId !== userData.userId) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
}
// get basic user details
var userObj = utils.getCleanUser(userData);
return res.json({ user: userObj, token });
});
});
app.listen(port, () => {
console.log('Server started on: ' + port);
});
That's it for today. Now you can check these APIs in postman or any other tools.
Output - Create REST API for authentication in Node.js using JWT - Clue Mediator
In Part 3 of this article, we'll create login form in ReactJS using secure REST API
In this article, we have covered the general straight forward flow of the authentication. Check out the below article where you will find the more secure way to implement authentication including refresh token and CSRF protection.
Login App with CSRF protection
Thanks for reading. Happy Coding!