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.
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.
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.
1 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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
1 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | // 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.
1 2 3 4 5 6 7 8 | // 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 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.
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 protectionThanks for reading. Happy Coding!
Hi Clue,
Thanks for the article!!!
I wonder how to create not “static user details” … for instance json file or something like that. I want create more admins
Hello Vova,
I’m glad you like the article.
Below code will help you to read/write json file instead of static users.
var fs = require('fs');
...
...
var users = [];
...
fs.readFile('jsonfile.json', 'utf8', function readFile(err, data){
if (err){
console.log(err);
return false;
}
const obj = JSON.parse(data); // parse data from string
obj.push({id: 2, square:3}); // add some data
const json = JSON.stringify(obj); // convert it back to JSON format
fs.writeFile('jsonfile.json', json, 'utf8', callback); // write it back
}});
...
...
Like & Share with your friends. Happy Coding..!!
Thanks Clue!
This part of code should have separate file? or I can add it to server.js file?
I made something like this:
const users = [
{
userId: “789789”,
password: “123456”,
name: “Mike X”,
username: “mike”,
isAdmin: true
},
{
userId: “7333333”,
password: “123456”,
name: “Joe”,
username: “joe”,
isAdmin: true
},
]
let userData = users.find(obj =>{
return obj.username === “joe”
})
How can I check “username” as variable instead of write “joe” ?
Hello Vova,
I would recommend you to take separate file instead of variable in server.js file. You can also use database instead of it.
– Thanks
Hi clue, I’m getting a ‘token not defined’ on utils.js file
Hi Edwin,
Sorry, We made a mistake in “generateToken” function. Can you please check it and let me know if you are still facing an issue.
Thank you for pointing our attention there.
Follow us on Facebook & Twitter to get latest update.
– Clue Mediator
i’m not able to perform multi-user auth for above example …can you guys help with sample code or stuff?
Hi Abhijit,
What do you mean by multi-user auth? Can you please explain more?
We’ll try our best to help you.
yeah like above example is for static single user sign-in ,
i’m trying to implement sign-ins for more than one user…like have 4 users, 2 are admins and like that
i’m noobie in node backend, thanks for help
Hi Abhijit,
You have to implement the role based application to manage the multi role user login.
Let me add this topic in my list. We will write separate article on it.
You can subscribe us for weekly email update of our news & articles.
Like us on Facebook & Share it. Happy Coding..!!!
– Clue Mediator
Ok….looking forward to it
Hello Abhijit,
We have published a new article where we explained the secure way to implement the login application. Hope this clarifies your concern.
Login App with CSRF protection – Understanding authentication using JWT access token and refresh token
Happy Coding…!!
Hello,
very nice article to read and to understand how that all works. I have one question: If I have other backend routes too, that should be protected by the token how do I verify that the user is loggedin ?
Hello Tobias,
We glad you like it.
Let’s talk about your queries. Are you talking about the other backend technologies or other private routes?
If you are talking about the private routes then you should have separate middleware where you can verify the token for each request and based on that you can manage the logged-in status.
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 – Understanding authentication using JWT access token and refresh token
We are still working on it to serve two more articles related to it.
Hope you like it.
Subscribe us for weekly updates or like and follow us for regular updates.
– Clue Mediator
thanks Clue. The linked article sounds like what I am searching for. I am looking forward to read it if it is finished.
Great, You will get a bunch of articles by next week.
Keep in touch and share it with your friends.
Happy Coding..!!
Hey Clue! While posting signin request over Postman, I’m getting following error:
{
“error”: true,
“message”: “Username or Password required.”
}
I checked with your code..everything is same still I’m getting this error
Hello Gurudeep,
Are you passing the username and password via users/signin post request? You can also clone the Github repository and use the postman collection that we have provided at the bottom of the post because I have tested it and it’s working with the existing demo.
Let me know if you are still facing any issues.
Subscribe us for weekly updates or like and follow us for regular updates.
Happy Coding..!!
Hi,
Thanks for this!
Do you familiar with the problem of :
You need to enable JavaScript to run this app.
when trying to run GET request from postman for “http://localhost:3000” ?
I would guess your GET request URL is wrong. Please try to access it from the browser so you can get more idea about the error.
Hi,
Thanks for this!
Can you please give register form example with same flow
Hi Kamal,
You can create a Registration form with validation and use the current article to implement login functionality.
Check out another article to implement Login App with CSRF protection – Understanding authentication using JWT access token and refresh token.
Feel free to share your query with us.
Subscribe us for weekly updates or like and follow us for regular updates.
can you please let me know where to add the below code to add multiple users instead of static users?
var fs = require(‘fs’);
…
…
var users = [];
…
fs.readFile(‘jsonfile.json’, ‘utf8’, function readFile(err, data){
if (err){
console.log(err);
return false;
}
const obj = JSON.parse(data); // parse data from string
obj.push({id: 2, square:3}); // add some data
const json = JSON.stringify(obj); // convert it back to JSON format
fs.writeFile(‘jsonfile.json’, json, ‘utf8’, callback); // write it back
}});
…
…
Hello Saif,
In the current article, we are only reading the data to verify them. So I suggest you create a new promise based function and write code to get the list of the user from the JSON file. Call this newly created method from signin API.
Let us know if you still have any doubts.
Where is the /users/signin coming from? I get an error 404 whenever I try to POST to it.
Hi Will,
I think you forgot to implement /users/signin API. Look at this link for your reference. You can also check the repository at the end of the page.
Hi Clue Mediator, thank for this article
i want to ask, how to read user data from API JSON Response?
Hi Oryz,
Please check out the following article to read the data from the API JSON response and display it on the page.
API calls with React Hooks
no, that’s not what I mean, i want to get userData in this article from API response.
in this article userData get from static data, but i want to get userData from other API like a “https://jsonplaceholder.typicode.com/users”, how to fetch/axios from that’s API source and check username password from my form?how to add fetch or axios in server.js? is it possible to fetch from other API in server.js?
i have a backend website and develop with symfony, i create API with it
i develop frontend with reactjs, and want to login with userData from API source in symfony
Yes, you can use the
node-fetch
npm package to manage the API call.I’ve tried to do that, with fetch or axios in server.js before compare username password but no response and no error, i tried put axios in login.js and work, but why didn’t work in server.js?
Can you please check the Console or Network tabs? Is there any CORS error?
Hi Clue… I really appreciate your work. It’s quite impressive. With that being said, I am a novice at coding, however, I’m having issues myself logging in as I’m coming up empty with your code. If you could please assist, it would me appreciated. Thank you so much!
Hi Josh,
At the end of the article, you will find the working demo GitHub source code. You can use the postman collection for the testing.
hi Clue mediator very thank for your tutorial i try do follow you but when i try test api it have problem with function post. when post it message cannot post users/singin.. please help explain me. thanks.
Hi Hort, Can you please clone the git repository and test again? If you are still facing any issues then share your code through contact email.
Thanks
20 |Unhandled Rejection (TypeError): Cannot read property ‘status’ of undefined
setLoading(false);
21 |
22 |
> 23 | if (error.response.status === 401) setError(error.response.data.message);
| ^ 24 | else setError(“Something went wrong. Please try again later.”);
25 |
26 | });
Resolve the error
Can you please check the error.response?
Hi Clue,
I am new to this, when i am using postman
For:
http://localhost:4000/user/signin
getting empty response or can not get /user/signin 400 Bad requestThanks !!
Hi Arjun, Use the
http://localhost:4000/users/signin
. Thes
is missing in theusers
path.