{"id":4031,"date":"2024-03-06T11:51:23","date_gmt":"2024-03-06T11:51:23","guid":{"rendered":"https:\/\/www.skillvertex.com\/blog\/?p=4031"},"modified":"2024-03-06T11:51:23","modified_gmt":"2024-03-06T11:51:23","slug":"mern-stack-authentication-tutorial","status":"publish","type":"post","link":"https:\/\/www.skillvertex.com\/blog\/mern-stack-authentication-tutorial\/","title":{"rendered":"MERN Stack Authentication Tutorial 2024"},"content":{"rendered":"\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\" id=\"rank-math-toc\"><p>Table of Contents<\/p><nav><ul><li ><a href=\"#mern-stack-authentication-tutorial\">MERN Stack Authentication Tutorial <\/a><\/li><li ><a href=\"#installing-5-packages\">Installing 5 Packages <\/a><\/li><li ><a href=\"#mongoose-user-schema\">Mongoose User Schema<\/a><ul><li ><a href=\"#models-user-js\">\/models\/user.js<\/a><\/li><\/ul><\/li><li ><a href=\"#register\">Register<\/a><ul><li ><a href=\"#server-js\">server.js<\/a><\/li><\/ul><\/li><li ><a href=\"#understanding-jw-ts\">Understanding JWTs<\/a><\/li><li ><a href=\"#sign-json-web-token-login\">Sign JSON Web Token \/ Login<\/a><\/li><li ><a href=\"#verify-json-web-token\">Verify JSON Web Token\u00a0<\/a><\/li><li ><a href=\"#accessing-the-current-user\">Accessing The Current User<\/a><\/li><li ><a href=\"#logging-out\">Logging Out<\/a><\/li><li ><a href=\"#mern-stack-authentication-tutorial-part-2-the-frontend\">MERN Stack Authentication Tutorial (Part 2 &#8211; The Frontend)<\/a><\/li><li ><a href=\"#packages-to-install\">Packages To Install<\/a><\/li><li ><a href=\"#file-structure\">File Structure<\/a><\/li><li ><a href=\"#react-router-setup\">React Router Setup<\/a><\/li><li ><a href=\"#fetch-requests\">Fetch Requests\u00a0<\/a><\/li><li ><a href=\"#login\">Login <\/a><\/li><li ><a href=\"#register-1\">Register<\/a><\/li><li ><a href=\"#data-validation\">Data Validation<\/a><\/li><li ><a href=\"#private-routes-profile-page\">Private Routes (Profile Page)<\/a><\/li><li ><a href=\"#dynamically-rendering-navbar\">Dynamically Rendering Navbar<\/a><\/li><li ><a href=\"#where-to-store-jw-ts\">Where to store JWTs<\/a><\/li><li ><a href=\"#faq-mern-stack-authentication-tutorial-2024\">FAQ- MERN Stack Authentication Tutorial 2024<\/a><\/li><\/ul><\/nav><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mern-stack-authentication-tutorial\">MERN Stack Authentication Tutorial <\/h2>\n\n\n\n<p>Welcome to the MERN Stack Authentication Tutorial 2024! In this tutorial, we&#8217;ll guide you step-by-step on how to add a secure login system to your web applications using MongoDB, Express.js, React.js, and Node.js. Whether you&#8217;re new to web development or want to boost your skills, join us in creating a strong authentication setup for your MERN stack projects. Let&#8217;s make your applications more secure and user-friendly together!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"installing-5-packages\">Installing 5 Packages <\/h2>\n\n\n\n<p>Initially, we have to install  these 5 packages with npm or yarn<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm i express\nnpm i bcrypt\nnpm i jsonwebtoken\nnpm i mongoose\nnpm i body-parser<\/code><\/pre>\n\n\n\n<p>In our authentication setup, we use <strong>bcrypt <\/strong>to keep passwords safe in the database. JSON Web Tokens (JWTs), managed by the<strong> jsonwebtoken <\/strong>package, help us check if a user can access specific parts of our app. Just to clarify, authorization is about access rights, while authentication, during login, is about confirming a user&#8217;s identity. <strong>Mongoose <\/strong>helps us connect to our database, and <strong>body-parser<\/strong> makes it easy to get data from React in our requests. These tools work together to create a secure and user-friendly authentication system.<\/p>\n\n\n\n<p><strong>server.js<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"570\" height=\"408\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-2.png\" alt=\"\" class=\"wp-image-4086\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mongoose-user-schema\">Mongoose User Schema<\/h2>\n\n\n\n<p>Now, let&#8217;s craft a model to define how each user will be organized in our database. Users are usually represented as objects with five properties: username, email, password, and the id indicating when they were created. MongoDB automatically gives us the id, but we need to guide mongoose on how the other data should appear. To do this, we use a Schema, which takes an object representing our data structure. We&#8217;ll refer to this model later when creating our register route, as each user will rely on it during the registration process.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"models-user-js\">\/models\/user.js<\/h3>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"511\" height=\"163\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-1.png\" alt=\"\" class=\"wp-image-4085\"\/><\/figure>\n\n\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--D5JvM9Bk--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/bn07z5o0hj5384kjuyvf.png\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--D5JvM9Bk--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/bn07z5o0hj5384kjuyvf.png\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"register\">Register<\/h2>\n\n\n\n<p>While we haven&#8217;t built the frontend for our registration system, let&#8217;s imagine we have fields for username, email, and password that send a JSON object with this data to our &#8220;\/register&#8221; route. Thanks to our body-parser middleware, we can access this post data in req.body. Now, at the beginning of our server.js file, let&#8217;s require some useful modules. While JWTs will play a role in the login system, the register route requires access to the User schema and bcrypt as well. These modules will help us handle user data and ensure secure password storage.<\/p>\n\n\n\n<p>A process for user registration using Mongoose and bcrypt in a Node.js application. This process involves checking if the username or email is already in the database, hashing the password using bcrypt, and then saving the user information to the database.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"server-js\">server.js<\/h3>\n\n\n<div class=\"gb-container gb-container-7f376198\">\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"653\" height=\"215\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image.png\" alt=\"\" class=\"wp-image-4084\"\/><\/figure>\n\n<\/div>\n\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--s9AEHtvC--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/jq3t9umalv4f2rtd4waq.png\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--s9AEHtvC--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/jq3t9umalv4f2rtd4waq.png\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Check if the user already exists in the database:<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use Mongoose&#8217;s <code>findOne<\/code> method on the <code>User<\/code> model.<\/li>\n\n\n\n<li>Ensure that the <code>findOne<\/code> method is awaited to prevent the if statement from executing before the database check is complete.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>   const existingUser = await User.findOne({ $or: &#91;{ username: req.body.username }, { email: req.body.email }] });\n\n   if (existingUser) {\n       return res.json({ message: 'Username or email already exists' });\n   }<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\">\n<li><strong>Hash the password using bcrypt:<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use bcrypt&#8217;s <code>hash<\/code> method to securely hash the user&#8217;s password.<\/li>\n\n\n\n<li>The second parameter (salt rounds) determines the complexity of the hashing algorithm. Higher values increase security but also require more processing time.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>   const hashedPassword = await bcrypt.hash(req.body.password, 10); \/\/ 10 rounds<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"3\">\n<li><strong>Create and save the user in the database:<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use the information provided in the user schema to create a new user object.<\/li>\n\n\n\n<li>Save the user object to the database using the <code>save<\/code> method.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>   const newUser = new User({\n       username: req.body.username,\n       email: req.body.email,\n       password: hashedPassword,\n   });\n\n   await newUser.save();<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"4\">\n<li><strong>Consistent <code>res.json()<\/code> calls:<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ensure consistency in the keys used in the <code>res.json()<\/code> calls to prevent issues on the frontend.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>   return res.json({ message: 'User registered successfully' });<\/code><\/pre>\n\n\n\n<p>This process provides a secure way to register users, check for existing usernames or emails, hash passwords, and save user information in the database. Always remember to handle errors appropriately and provide meaningful responses to the client.<\/p>\n\n\n\n<p>Our server.js file will be much more complicated from the login system, so It is recommended to  create a separate file for authentication routes and import it into your server.js file<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"understanding-jw-ts\">Understanding JWTs<\/h2>\n\n\n\n<p>a.<strong>Purpose of JWTs in Authentication:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JWTs are used to manage user authentication in web applications.<\/li>\n\n\n\n<li>They allow the server to generate a token representing the user&#8217;s identity upon successful login.<\/li>\n\n\n\n<li>This token is then sent to the frontend and can be stored securely in either <code>localStorage<\/code> or cookies.<\/li>\n<\/ul>\n\n\n\n<p>b.<strong>Token Generation on Login:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When a user logs in, the server generates a JWT containing information about the user.<\/li>\n\n\n\n<li>This information is often referred to as &#8220;claims&#8221; and can include user ID, username, roles, and any other relevant data.<\/li>\n\n\n\n<li>The server signs the JWT with a secret key to ensure its integrity and authenticity.<\/li>\n<\/ul>\n\n\n\n<p>c.<strong>Token Decoding:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The frontend receives the JWT and stores it securely.<\/li>\n\n\n\n<li>Whenever the user makes subsequent requests to the server, the JWT is included in the request headers.<\/li>\n\n\n\n<li>The server can then decode the JWT using the secret key to verify the user&#8217;s identity.<\/li>\n<\/ul>\n\n\n\n<p>d.<strong>Storage of JWTs:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JWTs can be stored in either <code>localStorage<\/code> or cookies on the client side.<\/li>\n\n\n\n<li><code>localStorage<\/code> is a client-side storage mechanism, while cookies are sent automatically with each HTTP request.<\/li>\n\n\n\n<li>The choice between these two options often depends on security considerations and application requirements.<\/li>\n<\/ul>\n\n\n\n<p>e.<strong>Preserving Token Across Page Refresh:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Storing the JWT in <code>localStorage<\/code> or cookies ensures that the token is not lost when the user refreshes the page.<\/li>\n\n\n\n<li>This allows the user to remain authenticated even after a page reload.<\/li>\n<\/ul>\n\n\n\n<p>In summary, JWTs provide a secure and efficient way to manage user authentication by allowing the server to issue tokens that represent the user&#8217;s identity. These tokens are then securely stored on the client side and used to authenticate subsequent requests to protected resources.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"sign-json-web-token-login\">Sign JSON Web Token \/ Login<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"421\" height=\"559\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-3.png\" alt=\"\" class=\"wp-image-4087\"\/><\/figure>\n\n\n\n<p>In the login post request, the process begins by extracting user information from the incoming request and searching the database for the corresponding username. Handling the returned promise with a <code>.then<\/code>, the code checks if the user exists, and if not, a response is sent indicating that the provided username or password is invalid. Upon confirming the user&#8217;s existence, the password is validated using the <code>crypto<\/code> library&#8217;s <code>compare<\/code> method. If the password is deemed valid, the flow proceeds to the generation and signing of a JSON Web Token (JWT) using the <code>jwt.sign<\/code> function. The payload of the JWT typically includes user-specific information like the username, user ID, and email. It&#8217;s emphasized to securely store the secret key used for encryption in environment variables. Additional options, such as token expiration time, can be specified in the options object. The resulting signed JWT is then sent to the frontend, prefixed with &#8220;Bearer,&#8221; following the convention for token-based authentication. Proper error handling is implemented throughout the process to address potential issues with database queries, password comparison, and JWT signing. This approach enables secure user authentication and facilitates subsequent interactions with the application&#8217;s protected resources.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"verify-json-web-token\">Verify JSON Web Token&nbsp;<\/h2>\n\n\n\n<p>After successfully creating a JSON Web Token (JWT) for user sign-in, the next step involves implementing a mechanism to verify whether the user accessing a particular route is the same individual who logged in. The jsonwebtoken library conveniently provides a <code>.verify()<\/code> method to facilitate this verification process.<\/p>\n\n\n\n<p>To achieve this, a middleware function can be crafted to handle user verification, and this middleware is placed before each route that requires protection. If the verification fails, the <code>next()<\/code> function is not invoked in the middleware, preventing the user from accessing the data associated with a specific route. Instead, an object detailing the user&#8217;s access capabilities is sent back. The <code>isLoggedIn<\/code> property is set to false if the verification fails. On the other hand, if the verification succeeds, the middleware allows progression to the route, and the response includes <code>isLoggedIn<\/code> set to true.<\/p>\n\n\n\n<p>Additionally, when advancing to the next route, specific properties of the decoded user from the JWT can be utilized within the route call. For instance, <code>req.user<\/code> can be employed, and the decoded username and ID can be set to <code>req.user.id<\/code> and <code>req.user.username<\/code>, respectively. This allows for personalized handling of user-specific data within the protected route.<\/p>\n\n\n\n<p>This middleware-based approach to user verification enhances the security of the application by ensuring that only authenticated users with valid JWTs can access protected routes. The decoded user information from the JWT further empowers these routes to provide customized responses based on the user&#8217;s identity and access privileges.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"577\" height=\"341\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-4.png\" alt=\"\" class=\"wp-image-4088\"\/><\/figure>\n\n\n\n<p>In the given code, we start by grabbing a token from the request headers. In the front end, we need to set a header called &#8220;x-access-token&#8221; and put the token there (usually from <code>localStorage<\/code>). After getting the token, we remove the &#8220;Bearer&#8221; part, leaving only the token. Then, we use <code>jwt.verify()<\/code> with the token, the secret key used before, and a callback function. The callback function gets the user data from decoding the token, and we set this user data to <code>req.user<\/code>. Now, any upcoming route can access <code>req.user<\/code> for personalized user details. If the token is missing or fails to authenticate, we send <code>{ isLoggedIn: false }<\/code> back to the front end. This informs the client side to redirect the user, often handled with tools like React Router. This way, the application ensures that unauthorized users are redirected, improving overall security and user experience.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"accessing-the-current-user\">Accessing The Current User<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"563\" height=\"131\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-5.png\" alt=\"\" class=\"wp-image-4089\"\/><\/figure>\n\n\n\n<p>By adding the <code>verifyJWT<\/code> middleware as the second parameter in the <code>app.get()<\/code> method, we can use the current user&#8217;s data in any route we want. This middleware checks and decodes the user&#8217;s JSON Web Token, making the user information accessible through <code>req.user<\/code>. This way, we can easily handle personalized user data in specific routes, making our application more secure and customizable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"logging-out\">Logging Out<\/h2>\n\n\n\n<p>We can delete the token from localStorage (which can be done with a simple button click that will call localStorage.removeItem (&#8220;token&#8221;). Hence, the verifyJWT middleware will be failed and then, a response will be sent which says that isLoggedIn is set to false.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"mern-stack-authentication-tutorial-part-2-the-frontend\">MERN Stack Authentication Tutorial (Part 2 &#8211; The Frontend)<\/h2>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"packages-to-install\">Packages To Install<\/h2>\n\n\n\n<p>In this setup, we&#8217;ll install react-router to navigate between different routes. Each route fetches data from the server because the frontend is primarily responsible for interacting with the database. Unlike in NodeJS projects where you might use res.redirect for navigation, that approach won&#8217;t work here because the frontend and backend operate on different ports. The backend can&#8217;t directly instruct the frontend to redirect; it can only send and receive data.<\/p>\n\n\n\n<p>Since we can&#8217;t rely on express for routing, we turn to react-router. If you&#8217;re familiar with express, you might know that engines like EJS or Pug are often used for dynamic data rendering. In our case, React serves as our view engine. However, unlike traditional view engines, we can&#8217;t directly pass data from the backend to React. Instead, we need to fetch the data from the backend within the React components. This approach allows us to dynamically display the data received from the server.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"file-structure\">File Structure<\/h2>\n\n\n\n<p>To manage the flow of our application, we&#8217;ll create components for the login, register, and protected profile pages. These components will serve as the building blocks for our app&#8217;s user authentication system.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"react-router-setup\">React Router Setup<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"589\" height=\"287\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-6.png\" alt=\"\" class=\"wp-image-4097\"\/><\/figure>\n\n\n\n<p>In our App.js component, we make use of three components from react-router that allow us to define route names and specify which component to render on those routes. We can even render dynamic routes by using a colon followed by a variable name, as demonstrated in the case of the Profile Page route. It&#8217;s important to include the <code>exact<\/code> attribute in each of the Route components to ensure proper routing. Without it, nested routes like &#8220;\/first\/second\/third\/page&#8221; might halt at &#8220;\/&#8221;.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"fetch-requests\">Fetch Requests&nbsp;<\/h2>\n\n\n\n<p>When making fetch requests in each component, it&#8217;s crucial to understand their structure and why certain elements are included. In a POST request, used to send login information to the backend, headers play a pivotal role in providing context to the recipient. Two key headers utilized are &#8220;Content-type: application\/json&#8221; and &#8220;x-access-token: localStorage.getItem(&#8216;token&#8217;).&#8221;<\/p>\n\n\n\n<p>The &#8220;Content-type&#8221; header informs the receiver that JSON data is being sent and is required for every POST request. The second header, as mentioned earlier, is passed to routes requiring user authorization. More details on the localStorage part will be explained later, but for now, remember that this second header is employed when fetching data specific to each user.<\/p>\n\n\n\n<p>Moreover, the fetch request doesn&#8217;t need to explicitly specify &#8220;localhost:BACKEND_PORT\/exampleroute&#8221; if a proxy is set in package.json to redirect to the backend. In this case, you can simply write &#8220;\/exampleroute.&#8221;<\/p>\n\n\n\n<p>Beneath the headers, the request body must be included, consisting of the primary data to be sent. Ensure to use JSON.stringify for this body because only strings can be sent to the backend. The body parser middleware imported in the backend&#8217;s first part will parse this stringified object for further use.<\/p>\n\n\n\n<p>Since the fetch request returns a promise, the .then method can be employed to retrieve any data sent back from the backend after processing the request. This asynchronous nature facilitates effective communication between the frontend and backend components of the application.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"547\" height=\"466\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-7.png\" alt=\"\" class=\"wp-image-4098\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"login\">Login <\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"416\" height=\"565\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-8.png\" alt=\"\" class=\"wp-image-4099\"\/><\/figure>\n\n\n\n<p>In this section of code, the form submission process is managed by retrieving input values and initiating a request to the login route. This route is responsible for validating the user, confirming their existence, and creating a JSON Web Token for the user&#8217;s session. After the request is processed, the received token is set in localStorage for persistence across page refreshes and global availability within the application. However, it&#8217;s important to note that saving tokens in localStorage has both advantages and disadvantages, which will be discussed later.<\/p>\n\n\n\n<p>The subsequent block of code involves the useEffect hook. This code triggers a call to the &#8216;\/isUserAuth&#8217; route, specifically designed to verify if the user is logged in by checking the presence of the correct token. The x-access-token header is crucial for this verification. If the login fails, nothing happens. However, upon successful login, the JSON Web Token is validated, and the React Router&#8217;s history API is employed to redirect the user to the home page. Since the useEffect is executed when the component is mounted, it ensures that a logged-in user cannot access the login page as they are immediately redirected by this useEffect call.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"register-1\">Register<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"453\" height=\"559\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-9.png\" alt=\"\" class=\"wp-image-4100\"\/><\/figure>\n\n\n\n<p>The register component is very similar to the login component. The main difference is that, in the register component, we call the register route. This route creates a new user in our database. After the user successfully fills out the form, they are automatically redirected to the login page. The form setup and how we handle it are almost the same as in the login component, making the code straightforward and easy to understand.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"data-validation\">Data Validation<\/h2>\n\n\n\n<p>For both the register and login routes, it&#8217;s crucial to incorporate data validation to safeguard against potential issues that users might cause. It&#8217;s recommended to use an external package for this purpose, as they are generally more secure and less prone to errors compared to implementing your own solution.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"private-routes-profile-page\">Private Routes (Profile Page)<\/h2>\n\n\n\n<p>Before progressing, it&#8217;s important to note that for any private route, the &#8216;\/isUserAuth&#8217; route defined in the backend section of this two-part tutorial series should be invoked. This route verifies the presence of a valid JSON Web Token and, if valid, returns essential user information, such as the username. This mechanism ensures the authentication and authorization of users attempting to access private routes in the application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"dynamically-rendering-navbar\">Dynamically Rendering Navbar<\/h2>\n\n\n\n<p>You might wonder why I didn&#8217;t put the Navbar in the App.js component. While it would be convenient to have it there for every page, doing so would keep the Navbar the same on every page. However, the Navbar often includes buttons for login, register, or logout. It&#8217;s better to re-render these buttons dynamically when the user goes to a new page, so I choose not to make the Navbar static across the entire app.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"503\" height=\"559\" src=\"https:\/\/www.skillvertex.com\/blog\/wp-content\/uploads\/2023\/11\/image-10.png\" alt=\"\" class=\"wp-image-4101\"\/><\/figure>\n\n\n\n<p>To achieve this, we start by fetching the &#8216;\/isUserAuth&#8217; route to confirm that the user is logged in. If they are, we can retrieve their username and display it in the Navbar if desired. Moving to the JSX part, we conditionally render the login\/logout buttons based on whether the username has been set. If it&#8217;s set, we render the logout button because we know the user is logged in. Otherwise, we render the login\/register buttons, both using the Link component from react-router for easy navigation to those pages. Finally, the logout button triggers a logout function. This function deletes the token from localStorage and redirects the user to the login page. This redirection is crucial for re-rendering our Navbar. Alternatively, we could achieve the same by refreshing the page after deleting the token using history.go(0).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"where-to-store-jw-ts\">Where to store JWTs<\/h2>\n\n\n\n<p>There are three main options for storing data in the browser: local storage, session storage, and cookies.<\/p>\n\n\n\n<p>Local storage and session storage are simpler to implement but are susceptible to XSS (Cross-Site Scripting) attacks.<\/p>\n\n\n\n<p>Cookies, while more secure against XSS attacks, are vulnerable to CSRF attacks. However, using an httpOnly cookie can enhance security.<\/p>\n\n\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--tlFhW7RV--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/y1zg1c97558ss3033jhp.png\" rel=\"nofollow noopener\" target=\"_blank\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"faq-mern-stack-authentication-tutorial-2024\">FAQ- MERN Stack Authentication Tutorial 2024<\/h2>\n\n\n<div id=\"rank-math-faq\" class=\"rank-math-block\">\n<div class=\"rank-math-list \">\n<div id=\"faq-question-1701249331407\" class=\"rank-math-list-item\">\n<h4 class=\"rank-math-question \">Q1. How do I authenticate my MERN stack?<\/h4>\n<div class=\"rank-math-answer \">\n\n<p>Ans.If the user doesn&#8217;t exist, the process continues to encrypt the password using the bcrypt module. Once the encryption is complete and the user is successfully created, a 200 status code is returned. Moving on to the login route, the system checks whether the provided user email and password match with the stored credentials.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1701249340876\" class=\"rank-math-list-item\">\n<h4 class=\"rank-math-question \">Q2. Is there a future for MERN stack?<\/h4>\n<div class=\"rank-math-answer \">\n\n<p>Ans. Choosing the MERN stack (MongoDB, Express.js, React, and Node.js) is a great decision for building modern web apps. It&#8217;s easy to learn, performs well, and is expected to stay important in the tech world for a long time.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1701249346171\" class=\"rank-math-list-item\">\n<h4 class=\"rank-math-question \">Q3. What is two factor authentication in MERN stack?<\/h4>\n<div class=\"rank-math-answer \">\n\n<p>Ans.The initial endpoint, \/api\/generate-2fa-secret, is designed to create and save a two-factor authentication (2FA) secret for a user. Meanwhile, the subsequent endpoint, \/api\/verify-otp, serves the purpose of confirming that the user can generate valid one-time passwords (OTPs) with the provided 2FA secret, typically using an authenticator app. Once successful, this process enables two-factor authentication for the user.<\/p>\n\n<\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>MERN Stack Authentication Tutorial Welcome to the MERN Stack Authentication Tutorial 2024! In this tutorial, we&#8217;ll guide you step-by-step on how to add a secure login system to your web applications using MongoDB, Express.js, React.js, and Node.js. Whether you&#8217;re new to web development or want to boost your skills, join us in creating a strong &#8230; <a title=\"MERN Stack Authentication Tutorial 2024\" class=\"read-more\" href=\"https:\/\/www.skillvertex.com\/blog\/mern-stack-authentication-tutorial\/\" aria-label=\"More on MERN Stack Authentication Tutorial 2024\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":5490,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[736],"tags":[744],"class_list":["post-4031","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-mern-stack","tag-mern-stack-authentication-tutorial-2024","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-33"],"_links":{"self":[{"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/posts\/4031","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/comments?post=4031"}],"version-history":[{"count":10,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/posts\/4031\/revisions"}],"predecessor-version":[{"id":7964,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/posts\/4031\/revisions\/7964"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/media\/5490"}],"wp:attachment":[{"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/media?parent=4031"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/categories?post=4031"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skillvertex.com\/blog\/wp-json\/wp\/v2\/tags?post=4031"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}