<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Complete Auth Using MongoDB]]></title><description><![CDATA[Complete Auth Using MongoDB]]></description><link>https://authusingmongodbsundram.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 14 Oct 2026 10:40:29 GMT</lastBuildDate><atom:link href="https://authusingmongodbsundram.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Complete Auth Using MongoDB]]></title><description><![CDATA[Overview:
Authentication is one of the most essential components of web applications. It helps secure user data, ensures only authorized access to specific resources, and keeps malicious actors at bay. But if you're new to auth or feeling confused ab...]]></description><link>https://authusingmongodbsundram.hashnode.dev/complete-auth-using-mongodb</link><guid isPermaLink="true">https://authusingmongodbsundram.hashnode.dev/complete-auth-using-mongodb</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[@hiteshchoudharylco]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Chaiaurcode]]></category><category><![CDATA[ChaiCohort]]></category><category><![CDATA[#piyushgarag]]></category><dc:creator><![CDATA[Sundram Kumar]]></dc:creator><pubDate>Fri, 21 Mar 2025 15:06:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742565966148/370d6b12-9fa4-4d39-9583-ae6d1ace901c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Overview:</strong></p>
<p>Authentication is one of the most essential components of web applications. It helps secure user data, ensures only authorized access to specific resources, and keeps malicious actors at bay. But if you're new to auth or feeling confused about how all the pieces fit together, this blog is for you!</p>
<p>In this blog, we’ll go step by step, covering the core concepts and implementation of <strong>user authentication</strong> using <strong>MongoDB</strong>, <strong>Node.js</strong>, and <strong>JWT (JSON Web Tokens)</strong>. By the end of this blog, you’ll have a clear understanding of the authentication flow, including <strong>registration</strong>, <strong>login</strong>, <strong>password hashing</strong>, <strong>email verification</strong>, and more.</p>
<p>If you’ve ever wondered:</p>
<ul>
<li><p>"How does authentication actually work?"</p>
</li>
<li><p>"How do I securely store passwords?"</p>
</li>
<li><p>"What role do tokens play in authentication?"</p>
</li>
<li><p>"How do I manage user sessions securely?"</p>
</li>
<li><p>"How do I ensure that emails are verified before granting access?"</p>
</li>
</ul>
<p>This blog will answer all your questions in a structured, hands-on manner!</p>
<h2 id="heading-what-well-learn"><strong>What We’ll Learn:</strong></h2>
<p>In this blog, we will cover the following concepts and technologies step by step:</p>
<ol>
<li><p><strong>What is Authentication?</strong></p>
<ul>
<li><p>A clear understanding of what authentication is and why it's crucial.</p>
</li>
<li><p>The difference between <strong>authentication</strong> and <strong>authorization</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>How to Set Up MongoDB with Node.js</strong></p>
<ul>
<li><p>Integrating <strong>MongoDB Atlas</strong> (cloud-hosted MongoDB service) into your project.</p>
</li>
<li><p>How to configure <strong>MongoDB connection</strong> in a Node.js application.</p>
</li>
</ul>
</li>
<li><p><strong>Hashing Passwords</strong></p>
<ul>
<li>How to hash passwords securely using <strong>bcryptjs</strong> to ensure that no plaintext passwords are stored.</li>
</ul>
</li>
<li><p><strong>JWT (JSON Web Tokens)</strong></p>
<ul>
<li><p>Generating <strong>JWT tokens</strong> for securing user sessions.</p>
</li>
<li><p>How to send and receive JWT tokens using <strong>cookies</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>User Registration &amp; Login Flow</strong></p>
<ul>
<li><p>A full <strong>registration flow</strong> (with validation and email verification).</p>
</li>
<li><p>How to handle <strong>user login</strong> with <strong>JWT authentication</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>Email Verification</strong></p>
<ul>
<li><p>Sending <strong>verification emails</strong> using <strong>Nodemailer</strong> and <strong>Mailtrap</strong>.</p>
</li>
<li><p>How to generate a <strong>unique token</strong> for email verification.</p>
</li>
</ul>
</li>
<li><p><strong>Password Reset Flow</strong></p>
<ul>
<li>Implementing the <strong>forget password</strong> and <strong>reset password</strong> flow with email tokenization.</li>
</ul>
</li>
<li><p><strong>Middleware and Routing</strong></p>
<ul>
<li>Protecting routes with <strong>middleware</strong> to ensure that users are authenticated before accessing certain routes.</li>
</ul>
</li>
<li><p><strong>Testing &amp; Postman</strong></p>
<ul>
<li>How to test all your authentication routes using <strong>Postman</strong> and ensure your app is secure.</li>
</ul>
</li>
</ol>
<h2 id="heading-why-authentication-is-important"><strong>Why Authentication is Important?</strong></h2>
<p>In any web application, <strong>authentication</strong> is the process of verifying who a user is, whereas <strong>authorization</strong> refers to what they can access once logged in.</p>
<p>Imagine a banking application. Authentication ensures that only the legitimate user can access their bank account, while authorization defines what operations the user is allowed to perform within the account (e.g., viewing balance, transferring money, etc.).</p>
<p>In the context of our blog, we’ll focus on the authentication process, where we’ll create an <strong>authentication system</strong> that will:</p>
<ul>
<li><p>Register new users.</p>
</li>
<li><p>Verify their identity during login.</p>
</li>
<li><p>Issue tokens to keep users logged in securely.</p>
</li>
<li><p>Protect resources with middleware to ensure only authenticated users can access certain pages.</p>
</li>
</ul>
<h2 id="heading-step-by-step-guide"><strong>Step-by-Step Guide:</strong></h2>
<p>Let's break the flow down into simple steps to understand the full authentication system.</p>
<h3 id="heading-step-1-setting-up-the-project"><strong>Step 1: Setting Up the Project</strong></h3>
<ol>
<li><p><strong>Install Dependencies</strong><br /> You’ll need to set up your environment with Node.js, Express, and MongoDB. Key dependencies include:</p>
<ul>
<li><p><code>mongoose</code> (for MongoDB connection)</p>
</li>
<li><p><code>bcryptjs</code> (for password hashing)</p>
</li>
<li><p><code>jsonwebtoken</code> (for JWT generation)</p>
</li>
<li><p><code>nodemailer</code> (for sending verification emails)</p>
</li>
<li><p><code>cookie-parser</code> (to manage cookies for JWTs)</p>
</li>
</ul>
</li>
</ol>
<p>Run this command in your terminal:</p>
<pre><code class="lang-javascript">install mongoose bcryptjs jsonwebtoken nodemailer cookie-parser
</code></pre>
<ol>
<li><p><strong>MongoDB Atlas Setup</strong></p>
<ul>
<li><strong>MongoDB Atlas</strong> is a cloud-based database service. We’ll use it to host our MongoDB database and connect it securely to our Node.js application. You’ll need to create an account on MongoDB Atlas and get your connection string.</li>
</ul>
</li>
</ol>
<h3 id="heading-step-1-create-a-mongodb-atlas-account">Step 1: Create a MongoDB Atlas Account</h3>
<ol>
<li><p><strong>Go to MongoDB Atlas</strong>: Open your browser and go to <a target="_blank" href="https://www.mongodb.com/cloud/atlas">https://www.mongodb.com/cloud/atlas.</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>Sign Up</strong>: Click on the “Start</a> Free” b<a target="_blank" href="https://www.mongodb.com/cloud/atlas">utton to sign up. You can use your</a> Google account or email to create an account.</p>
</li>
</ol>
<h3 id="heading-step-2-create-a-new-clusterhttpswwwmongodbcomcloudatlas">Step <a target="_blank" href="https://www.mongodb.com/cloud/atlas">2: Create a New Cluster</a></h3>
<p>    <a target="_blank" href="https://www.mongodb.com/cloud/atlas">Once you'r</a>e logged into MongoDB Atlas:</p>
<ol>
<li><p><strong>Create a Cluster</strong>:</p>
<ul>
<li><p>In the Atlas dashboard, click on <a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>"Build a Cluster"</strong>.</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">You’ll be prompted to choose a cloud provi</a>der and <a target="_blank" href="https://www.mongodb.com/cloud/atlas">region for your database. The free tier (M0) is availab</a>le on most cloud pro<a target="_blank" href="https://www.mongodb.com/cloud/atlas">viders (AWS, GCP, or Azure) and reg</a>ions.</p>
</li>
<li><p>Select the <strong>Free Tier (M0)</strong> option, which gives you 512MB of storage (ideal for development and testing).</p>
</li>
<li><p>Click <strong>"Create Clus</strong><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>ter"</strong>.</a></p>
</li>
</ul>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>Cluster Creation Process</strong></a>:</p>
<ul>
<li>The creation process can take a few minutes. Once it's complete, yo<a target="_blank" href="https://www.mongodb.com/cloud/atlas">u'll see your cluster listed on the dashboard.</a></li>
</ul>
</li>
</ol>
<h3 id="heading-step-3-set-up-database-accesshttpswwwmongodbcomcloudatlas"><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Step 3: Set Up Database Access</a></h3>
<p>    <a target="_blank" href="https://www.mongodb.com/cloud/atlas">You’ll ne</a>ed to set up a database user to access your MongoDB cluster.</p>
<ol>
<li><p><strong>Create a Database Us</strong><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>er</strong>:</a></p>
<ul>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">In the Atlas dashboard, go to the <strong>Database Access</strong> tab.</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Cl</a>ick <strong>"Add New Database User"</strong>.</p>
</li>
<li><p>Provid<a target="_blank" href="https://www.mongodb.com/cloud/atlas">e a username and password for the user.</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">You can set specifi</a>c permissions for the u<a target="_blank" href="https://www.mongodb.com/cloud/atlas">ser. For simplicity, you can give them <strong>read and write access</strong> to any d</a>atabase (recom<a target="_blank" href="https://www.mongodb.com/cloud/atlas">mended for development).</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Click <strong>"</strong></a><strong>Add User"</strong>.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-step-4-set-up-network-access-ip-whitelisting">Step 4: Set Up Network Access (IP Whitelisting)</h3>
<p>    You need to allow your app to connect to MongoDB Atla<a target="_blank" href="https://www.mongodb.com/cloud/atlas">s from specific IP addresses.</a></p>
<ol>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>Whitelist Your IP Address</strong></a>:</p>
<ul>
<li><p>Go to the <a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>Network Access</strong> tab in the Atlas da</a>shboard.</p>
</li>
<li><p>Click <strong>"Add IP Address"</strong>.</p>
</li>
<li><p>You can eith<a target="_blank" href="https://www.mongodb.com/cloud/atlas">er:</a></p>
<ul>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Whitelist your current IP address by clicking on <strong>"Allow Ac</strong></a><strong>cess From Anywhere"</strong> (<a target="_blank" href="https://www.mongodb.com/cloud/atlas">this will allow connections from any IP address).</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Or add a specific IP address</a> or IP range from which your app will connect.</p>
</li>
</ul>
</li>
<li><p>Click <strong>"Confirm"</strong> to add your IP address.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-step-5-get-your-connection-stringhttpswwwmongodbcomcloudatlas"><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Step 5: Get Your Connection String</a></h3>
<p>    Now that your cluster is set up, you need to <a target="_blank" href="https://www.mongodb.com/cloud/atlas">connect your application to it usi</a>ng a conne<a target="_blank" href="https://www.mongodb.com/cloud/atlas">ction string.</a></p>
<ol>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>Get Connection Str</strong></a><strong>i</strong><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>ng</strong>:</a></p>
<ul>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Go to the <strong>Clusters</strong> tab in th</a>e Atlas dashboard.</p>
</li>
<li><p>Click <strong>"Connect"</strong> next to your cluster.</p>
</li>
<li><p>Choose <strong>"</strong><a target="_blank" href="https://www.mongodb.com/cloud/atlas"><strong>Connect Your Application"</strong>.</a></p>
</li>
<li><p><a target="_blank" href="https://www.mongodb.com/cloud/atlas">Copy the connection string (it</a> will look like <a target="_blank" href="https://www.mongodb.com/cloud/atlas">this):</a></p>
<pre><code class="lang-javascript">  mongodb+srv:<span class="hljs-comment">//&lt;username&gt;:&lt;password&gt;@cluster0.mongodb.net/test</span>
</code></pre>
<p>  <a target="_blank" href="https://www.mongodb.com/cloud/atlas">Replace <code>&lt;username&gt;</code> and <code>&lt;password&gt;</code></a> with the credentials you set up earlier.</p>
</li>
</ul>
</li>
</ol>
<ol start="2">
<li><strong>Environment Variables</strong><br /> We'll use the <code>dotenv</code> <a target="_blank" href="https://www.mongodb.com/cloud/atlas">package to manage sensitive inform</a>ation like database credentials, API keys, and secrets securely in the <code>.env</code> file.</li>
</ol>
<h3 id="heading-step-2-define-the-mongodb-schema"><strong>Step 2: Define the MongoDB Schema</strong></h3>
<p>Start by defining a <code>User</code> schema in <strong>MongoDB</strong> using <strong>Mongoose</strong>. This schema will contain user information like name, email, password, and additional fields for email verification and password reset functionality.</p>
<pre><code class="lang-javascript">mongoose <span class="hljs-keyword">from</span> <span class="hljs-string">"mongoose"</span>;
<span class="hljs-keyword">import</span> bcrypt <span class="hljs-keyword">from</span> <span class="hljs-string">"bcryptjs"</span>;

<span class="hljs-keyword">let</span> userSchema = <span class="hljs-keyword">new</span> mongoose.Schema({
    <span class="hljs-attr">name</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">password</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">role</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>,
        <span class="hljs-attr">enum</span>: [<span class="hljs-string">'user'</span>, <span class="hljs-string">'admin'</span>],
        <span class="hljs-attr">default</span>: <span class="hljs-string">'user'</span>
    },
    <span class="hljs-attr">isVerified</span>: {
        <span class="hljs-attr">type</span>: <span class="hljs-built_in">Boolean</span>,
        <span class="hljs-attr">default</span>: <span class="hljs-literal">false</span>
    },
    <span class="hljs-attr">verificationToken</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">resetPasswordToken</span>: <span class="hljs-built_in">String</span>,
    <span class="hljs-attr">resetPasswordExpires</span>: <span class="hljs-built_in">Date</span>
}, { <span class="hljs-attr">timestamps</span>: <span class="hljs-literal">true</span> });
</code></pre>
<p>Here we’ve set up the schema with the necessary fields. We’ll also hash the password before saving it to the database using a <strong>pre-save hook</strong>.</p>
<h3 id="heading-this-code-is-a-pre-save-middleware-in-mongoose-that-hashes-the-password-before-saving-the-user-document-to-the-database-lets-break-down-each-part">This code is a <strong>pre-save middleware</strong> in Mongoose that hashes the password before saving the user document to the database. Let's break down each part:</h3>
<pre><code class="lang-javascript">userSchema.pre(<span class="hljs-string">"save"</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">next</span>) </span>{
    <span class="hljs-comment">// If the password field is modified (or newly set)</span>
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isModified(<span class="hljs-string">"password"</span>)) {
        <span class="hljs-comment">// Hash the password using bcrypt and set it to the password field</span>
        <span class="hljs-built_in">this</span>.password = <span class="hljs-keyword">await</span> bcrypt.hash(<span class="hljs-built_in">this</span>.password, <span class="hljs-number">10</span>);
    }
    <span class="hljs-comment">// Proceed with the save operation after the password is hashed</span>
    next();
});
</code></pre>
<h3 id="heading-explanation">Explanation:</h3>
<ol>
<li><p><code>userSchema.pre("save", async function(next) { ... })</code>:</p>
<ul>
<li><p><code>pre('save')</code>: This is a Mongoose middleware that runs before the <code>save()</code> operation on the document. In this case, it is executed before saving the user document to the MongoDB database.</p>
</li>
<li><p><code>async function(next)</code>: The middleware function is asynchronous because password hashing (using <code>bcrypt</code>) involves waiting for promises to resolve (i.e., it requires an asynchronous operation). <code>next</code> is a function that you must call to pass control to the next middleware or to continue with the save operation.</p>
</li>
</ul>
</li>
<li><p><code>if (this.isModified("password")) { ... }</code>:</p>
<ul>
<li><p><code>this.isModified("password")</code>: This checks if the <code>password</code> field has been modified in the current document. This check is important because we don't want to hash the password every time the document is updated (for example, when other fields like the <code>name</code> or <code>email</code> are modified).</p>
</li>
<li><p>If the password <strong>is modified</strong> (or it’s a new user), then we proceed to hash the password.</p>
</li>
</ul>
</li>
<li><p><code>this.password = await bcrypt.hash(this.password, 10)</code>:</p>
<ul>
<li><p><code>bcrypt.hash(this.password, 10)</code>: This hashes the password using the <code>bcrypt</code> library. <code>this.password</code> refers to the current value of the password field in the document.</p>
</li>
<li><p><code>10</code>: This is the number of salt rounds used by <code>bcrypt</code> to hash the password. The higher the number of rounds, the more computationally expensive the hash will be, making it harder for attackers to brute-force. A typical value is 10.</p>
</li>
<li><p><code>await</code>: We use <code>await</code> because <code>bcrypt.hash()</code> is an asynchronous function, meaning it returns a promise. We need to wait for the password to be hashed before proceeding.</p>
</li>
</ul>
</li>
<li><p><code>next()</code>:</p>
<ul>
<li><code>next()</code>: This function is called to pass control to the next middleware in the chain or to continue with the save operation once the password is hashed. Without this call, the save operation will be blocked, and the document won't be saved to the database.</li>
</ul>
</li>
</ol>
<h3 id="heading-why-it-works">Why It Works:</h3>
<ul>
<li><p>When a user’s password is modified or created, this middleware ensures that the password is <strong>hashed</strong> before saving it to MongoDB.</p>
</li>
<li><p>If the password hasn’t been changed (i.e., it was not modified), this hook does nothing, and the save operation proceeds as usual without altering the password.</p>
</li>
</ul>
<h3 id="heading-step-3-email-setup-with-nodemailer"><strong>Step 3: Email Setup with Nodemailer</strong></h3>
<p>To send verification and password reset emails, we'll use <strong>Nodemailer</strong>. First, you need to install it:</p>
<pre><code class="lang-javascript">install nodemailer
</code></pre>
<p>Then, set up the email service. You can use services like <strong>Mailtrap</strong> (for development) or <strong>SendGrid</strong> (for production). Here's a sample setup with <strong>Nodemailer</strong> using <strong>Mailtrap</strong>:</p>
<pre><code class="lang-javascript">nodemailer <span class="hljs-keyword">from</span> <span class="hljs-string">'nodemailer'</span>;

<span class="hljs-keyword">const</span> transporter = nodemailer.createTransport({
    <span class="hljs-attr">service</span>: <span class="hljs-string">'smtp.mailtrap.io'</span>,
    <span class="hljs-attr">auth</span>: {
        <span class="hljs-attr">user</span>: process.env.MAILTRAP_USER,
        <span class="hljs-attr">pass</span>: process.env.MAILTRAP_PASS
    }
});

<span class="hljs-keyword">const</span> sendVerificationEmail = <span class="hljs-function">(<span class="hljs-params">user, verificationToken</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> mailOptions = {
        <span class="hljs-attr">from</span>: <span class="hljs-string">'your-email@example.com'</span>,
        <span class="hljs-attr">to</span>: user.email,
        <span class="hljs-attr">subject</span>: <span class="hljs-string">'Email Verification'</span>,
        <span class="hljs-attr">text</span>: <span class="hljs-string">`Click the following link to verify your email: http://sundramkumar.com/verify/<span class="hljs-subst">${verificationToken}</span>`</span>
    };

    transporter.sendMail(mailOptions, <span class="hljs-function">(<span class="hljs-params">error, info</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (error) {
            <span class="hljs-built_in">console</span>.log(error);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Verification email sent:'</span>, info.response);
        }
    });
};
</code></pre>
<p>You'll need to replace the <code>MAILTRAP_USER</code> and <code>MAILTRAP_PASS</code> values with your Mailtrap credentials (or the credentials for whatever service you're using). This function sends the verification email when a user registers.</p>
<h3 id="heading-1-user-registration-and-email-verification"><strong>1. User Registration and Email Verification</strong></h3>
<p>In this section, we handle the process of registering a new user and verifying their email address.</p>
<h4 id="heading-why-do-we-need-this"><strong>Why Do We Need This?</strong></h4>
<p>Before users can access protected routes, they need to be registered. After registration, we send an email with a verification link, ensuring that the user is who they say they are.</p>
<h4 id="heading-steps-in-the-registration-process"><strong>Steps in the Registration Process:</strong></h4>
<ol>
<li><p><strong>Collect User Input:</strong> We first grab the <code>name</code>, <code>email</code>, and <code>password</code> from the user's request body. If any of these are missing, we return a <strong>400 error</strong> and prompt the user to provide all fields.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> { name, email, password } = req.body;
 <span class="hljs-keyword">if</span> (!name || !email || !password) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"All fields are required"</span> });
 }
</code></pre>
</li>
<li><p><strong>Check for Existing User:</strong> We then check if there’s already an existing user with the same email. If we find one, we return an error message saying the user already exists.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> existingUser = <span class="hljs-keyword">await</span> User.findOne({ email });
 <span class="hljs-keyword">if</span> (existingUser) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User already exists"</span> });
 }
</code></pre>
</li>
<li><p><strong>Create a New User:</strong> If no user exists, we proceed to create a new user in the database. At this point, we also generate a <strong>verification token</strong> that will be sent to the user's email.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.create({ name, password, email });
</code></pre>
</li>
<li><p><strong>Send Verification Email:</strong> After successfully creating the user, we generate a token using <code>crypto</code> and send a verification email using <strong>Nodemailer</strong>. This email contains a link that, once clicked, verifies the user's account.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> token = crypto.randomBytes(<span class="hljs-number">32</span>).toString(<span class="hljs-string">"hex"</span>);
 user.verificationToken = token;
 <span class="hljs-keyword">await</span> user.save();

 <span class="hljs-keyword">const</span> transporter = nodemailer.createTransport({
     <span class="hljs-attr">host</span>: process.env.MAILTRAP_HOST,
     <span class="hljs-attr">port</span>: process.env.MAILTRAP_PORT,
     <span class="hljs-attr">secure</span>: <span class="hljs-literal">false</span>,
     <span class="hljs-attr">auth</span>: {
         <span class="hljs-attr">user</span>: process.env.MAILTRAP_USERNAME,
         <span class="hljs-attr">pass</span>: process.env.MAILTRAP_PASSWORD,
     },
 });

 <span class="hljs-keyword">let</span> mailOptions = {
     <span class="hljs-attr">from</span>: <span class="hljs-string">'"Magic Elves" &lt;from@example.com&gt;'</span>,
     <span class="hljs-attr">to</span>: user.email,
     <span class="hljs-attr">subject</span>: <span class="hljs-string">"Verify Your Email"</span>,
     <span class="hljs-attr">text</span>: <span class="hljs-string">`Please click on the following link to verify your account:
     <span class="hljs-subst">${process.env.BASE_URL}</span>/api/v1/users/verify/<span class="hljs-subst">${token}</span>`</span>
 };

 <span class="hljs-keyword">await</span> transporter.sendMail(mailOptions);
</code></pre>
</li>
</ol>
<h4 id="heading-what-happens-next"><strong>What Happens Next?</strong></h4>
<p>Once the user clicks the verification link in their email, they are redirected to a page where their email gets verified, and they are granted access to the application.</p>
<hr />
<h3 id="heading-2-email-verification"><strong>2. Email Verification</strong></h3>
<p>Once the user registers, they need to confirm their email. This step is essential to ensure the user’s email is valid and that they are not a bot or malicious user.</p>
<h4 id="heading-why-do-we-need-this-1"><strong>Why Do We Need This?</strong></h4>
<p>This prevents unauthorized users from accessing the system and ensures that the user is indeed the owner of the email they registered with.</p>
<h4 id="heading-steps-in-the-email-verification-process"><strong>Steps in the Email Verification Process:</strong></h4>
<ol>
<li><p><strong>Retrieve the Token:</strong> The token sent in the email is included in the URL, and we extract it from the request parameters.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> { token } = req.params;
</code></pre>
</li>
<li><p><strong>Check for Token Validity:</strong> We look for a user in the database whose verification token matches the one in the URL. If no user is found or if the token is invalid, we return an error.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ <span class="hljs-attr">verificationToken</span>: token });
 <span class="hljs-keyword">if</span> (!user) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Invalid token"</span> });
 }
</code></pre>
</li>
<li><p><strong>Mark User as Verified:</strong> Once the user is found, we update the <code>isverified</code> status to <code>true</code>, indicating that the email has been confirmed. We then remove the token to prevent reuse.</p>
<pre><code class="lang-javascript"> user.isverified = <span class="hljs-literal">true</span>;
 user.verificationToken = <span class="hljs-literal">undefined</span>;
 <span class="hljs-keyword">await</span> user.save();
</code></pre>
</li>
<li><p><strong>Send Success Response:</strong> Finally, we send a success message to the user, confirming their email verification.</p>
<pre><code class="lang-javascript"> res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User verified successfully"</span>, <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span> });
</code></pre>
</li>
</ol>
<h4 id="heading-what-happens-next-1"><strong>What Happens Next?</strong></h4>
<p>Once the user’s email is verified, they are able to log in and access protected routes.</p>
<hr />
<h3 id="heading-3-user-login"><strong>3. User Login</strong></h3>
<p>After the user registers and verifies their email, they can log in to the system.</p>
<h4 id="heading-why-do-we-need-this-2"><strong>Why Do We Need This?</strong></h4>
<p>Logging in allows users to authenticate themselves and access secure areas of the application.</p>
<h4 id="heading-steps-in-the-login-process"><strong>Steps in the Login Process:</strong></h4>
<ol>
<li><p><strong>Receive User Credentials:</strong> The user provides their email and password. If any of these are missing, we return a <strong>400 error</strong>.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> { email, password } = req.body;
 <span class="hljs-keyword">if</span> (!email || !password) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"All fields are required"</span> });
 }
</code></pre>
</li>
<li><p><strong>Check User Existence:</strong> We check if the email exists in the database. If the email is invalid, we return an error.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });
 <span class="hljs-keyword">if</span> (!user) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Invalid email or password"</span> });
 }
</code></pre>
</li>
<li><p><strong>Verify Password:</strong> Using <strong>bcrypt</strong>, we compare the password provided by the user with the one stored in the database. If the passwords don't match, we return an error.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> isMatch = <span class="hljs-keyword">await</span> bcrypt.compare(password, user.password);
 <span class="hljs-keyword">if</span> (!isMatch) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Invalid email or password"</span> });
 }
</code></pre>
</li>
<li><p><strong>Check Email Verification:</strong> If the user hasn't verified their email, we return an error instructing them to verify their email first.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">if</span> (!user.isverified) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Please verify your email."</span> });
 }
</code></pre>
</li>
<li><p><strong>Generate JWT Token:</strong> If everything checks out, we generate a <strong>JWT token</strong> that the user can use for subsequent requests. This token will expire in 24 hours.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> token = jwt.sign(
     { <span class="hljs-attr">id</span>: user._id },
     process.env.JWT_TOKEN,
     { <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">"24h"</span> }
 );
</code></pre>
</li>
<li><p><strong>Send Token in Cookie:</strong> We send the JWT token as a cookie to the user's browser. This allows the user to remain logged in across requests.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> cookieOptions = {
     <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">secure</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">maxAge</span>: <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>
 };
 res.cookie(<span class="hljs-string">"token"</span>, token, cookieOptions);
</code></pre>
</li>
<li><p><strong>Send Success Response:</strong> Finally, we return the user’s details and the JWT token, confirming a successful login.</p>
<pre><code class="lang-javascript"> res.status(<span class="hljs-number">200</span>).json({
     <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">message</span>: <span class="hljs-string">"Login successful"</span>,
     token,
     <span class="hljs-attr">user</span>: { <span class="hljs-attr">id</span>: user._id, <span class="hljs-attr">name</span>: user.name, <span class="hljs-attr">role</span>: user.role },
 });
</code></pre>
</li>
</ol>
<h4 id="heading-what-happens-next-2"><strong>What Happens Next?</strong></h4>
<p>Now that the user is logged in, they can access routes protected by authentication middleware, which verifies the JWT token before granting access.</p>
<hr />
<h3 id="heading-4-logout"><strong>4. Logout</strong></h3>
<p>When the user wants to log out, we simply clear their <strong>JWT token</strong> stored in the cookie.</p>
<h4 id="heading-steps-in-the-logout-process"><strong>Steps in the Logout Process:</strong></h4>
<ol>
<li><p><strong>Clear the Cookie:</strong> We remove the <code>token</code> cookie from the user's browser, effectively logging them out.</p>
<pre><code class="lang-javascript"> res.cookie(<span class="hljs-string">'token'</span>, <span class="hljs-string">''</span>, {
     <span class="hljs-attr">httpOnly</span>: <span class="hljs-literal">true</span>,
     <span class="hljs-attr">expires</span>: <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(<span class="hljs-number">0</span>) <span class="hljs-comment">// Expire immediately</span>
 });
</code></pre>
</li>
<li><p><strong>Send Success Response:</strong> Finally, we send a response confirming that the logout was successful.</p>
<pre><code class="lang-javascript"> res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">"Logged out successfully"</span> });
</code></pre>
</li>
</ol>
<h4 id="heading-what-happens-next-3"><strong>What Happens Next?</strong></h4>
<p>The user is logged out and needs to log in again to access protected routes.</p>
<h3 id="heading-5-forgot-password"><strong>5. Forgot Password</strong></h3>
<p>The <strong>Forgot Password</strong> route allows a user to request a password reset if they forget their password.</p>
<h4 id="heading-why-do-we-need-this-3"><strong>Why Do We Need This?</strong></h4>
<p>This feature is critical for account recovery. If a user forgets their password, they can request a reset email with a link to reset their password and regain access to their account.</p>
<h4 id="heading-steps-in-the-forgot-password-process"><strong>Steps in the Forgot Password Process:</strong></h4>
<ol>
<li><p><strong>Receive User's Email:</strong> The user provides their email address. If this email is not associated with any registered account, we return an error.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> { email } = req.body;

 <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ email });

 <span class="hljs-keyword">if</span> (!user) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">"User not found"</span> });
 }
</code></pre>
</li>
<li><p><strong>Generate Reset Token:</strong> We generate a <strong>unique token</strong> using <code>crypto.randomBytes()</code> and store this token in the user's record in the database. The token will be used to identify the reset request.</p>
<p> Additionally, we set an expiration time for the token (in this case, 10 minutes), so the user has a limited time to reset their password.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> token = crypto.randomBytes(<span class="hljs-number">32</span>).toString(<span class="hljs-string">"hex"</span>);
 user.resetPasswordToken = token;
 user.resetPasswordExpires = <span class="hljs-built_in">Date</span>.now() + <span class="hljs-number">10</span> * <span class="hljs-number">60</span> * <span class="hljs-number">1000</span>; <span class="hljs-comment">// Token expires in 10 mins</span>
</code></pre>
</li>
<li><p><strong>Save the Token and Expiration:</strong> We save the generated token and the expiration time in the database to ensure they can be validated later.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> user.save();
</code></pre>
</li>
<li><p><strong>Set Up Nodemailer for Sending Email:</strong> Next, we set up <strong>Nodemailer</strong> to send an email to the user with a reset link. The link contains the reset token, and the user can click on it to go to the password reset page.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> transporter = nodemailer.createTransport({
     <span class="hljs-attr">host</span>: process.env.MAILTRAP_HOST,
     <span class="hljs-attr">port</span>: process.env.MAILTRAP_PORT,
     <span class="hljs-attr">secure</span>: <span class="hljs-literal">false</span>,
     <span class="hljs-attr">auth</span>: {
         <span class="hljs-attr">user</span>: process.env.MAILTRAP_USERNAME,
         <span class="hljs-attr">pass</span>: process.env.MAILTRAP_PASSWORD,
     },
 });

 <span class="hljs-keyword">let</span> mailOptions = {
     <span class="hljs-attr">from</span>: <span class="hljs-string">'"Magic Elves" &lt;from@example.com&gt;'</span>,
     <span class="hljs-attr">to</span>: user.email,
     <span class="hljs-attr">subject</span>: <span class="hljs-string">"Password Reset Request"</span>,
     <span class="hljs-attr">text</span>: <span class="hljs-string">`Hello, 

     You requested a password reset. Please click the link below to reset your password:
     <span class="hljs-subst">${process.env.BASE_URL}</span>/api/v1/users/reset/<span class="hljs-subst">${token}</span>`</span>
 };

 <span class="hljs-keyword">await</span> transporter.sendMail(mailOptions);
</code></pre>
</li>
<li><p><strong>Send Success Response:</strong> After sending the email, we return a success response to the user confirming that the password reset request has been sent.</p>
<pre><code class="lang-javascript"> res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">"Password reset email sent"</span> });
</code></pre>
</li>
</ol>
<h4 id="heading-what-happens-next-4"><strong>What Happens Next?</strong></h4>
<p>The user receives an email with a reset link. This link includes the token, and they can use it to access the reset password page.</p>
<hr />
<h3 id="heading-6-reset-password"><strong>6. Reset Password</strong></h3>
<p>The <strong>Reset Password</strong> route allows a user to set a new password by verifying the token they received in the email. This is the step where the actual password change happens.</p>
<h4 id="heading-why-do-we-need-this-4"><strong>Why Do We Need This?</strong></h4>
<p>This route ensures that the user can update their password after receiving the reset link and provides a secure way to validate the token before updating the password.</p>
<h4 id="heading-steps-in-the-reset-password-process"><strong>Steps in the Reset Password Process:</strong></h4>
<ol>
<li><p><strong>Retrieve the Reset Token:</strong> We first retrieve the token from the request parameters (<code>req.params.token</code>) and the new password from the request body (<code>req.body.newPassword</code>).</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> { token } = req.params;
 <span class="hljs-keyword">const</span> { newPassword } = req.body;
</code></pre>
</li>
<li><p><strong>Verify the Token and Expiry Time:</strong> We search the database for a user who has the matching <strong>reset token</strong> and whose <strong>reset token has not expired</strong>. The token expiration time is checked to ensure that it hasn’t been more than 10 minutes since the reset request was made.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> user = <span class="hljs-keyword">await</span> User.findOne({ 
     <span class="hljs-attr">resetPasswordToken</span>: token,
     <span class="hljs-attr">resetPasswordExpires</span>: { <span class="hljs-attr">$gt</span>: <span class="hljs-built_in">Date</span>.now() } <span class="hljs-comment">// Token still valid</span>
 });
</code></pre>
<ul>
<li>If the token is invalid or expired, we return an error message stating that the token is invalid or expired.</li>
</ul>
</li>
</ol>
<pre><code class="lang-javascript">    <span class="hljs-keyword">if</span> (!user) {
        <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">false</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">"Invalid or expired token"</span> });
    }
</code></pre>
<ol start="3">
<li><p><strong>Update the User's Password:</strong> If the token is valid, we update the user’s password to the new one provided. For security reasons, it's best to hash the password (usually with <strong>bcrypt</strong>) before saving it. Here, we assume <code>newPassword</code> is already hashed or prepared for storage.</p>
<pre><code class="lang-javascript"> user.password = <span class="hljs-keyword">await</span> newPassword; <span class="hljs-comment">// Ideally, hash the password first with bcrypt</span>
</code></pre>
</li>
<li><p><strong>Clear the Reset Token and Expiry:</strong> After successfully updating the password, we clear the <strong>reset token</strong> and <strong>reset token expiration</strong> fields from the user's record in the database. This prevents the token from being used again.</p>
<pre><code class="lang-javascript"> user.resetPasswordToken = <span class="hljs-literal">undefined</span>;
 user.resetPasswordExpires = <span class="hljs-literal">undefined</span>;
</code></pre>
</li>
<li><p><strong>Save the Updated User:</strong> We save the updated user record with the new password.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">await</span> user.save();
</code></pre>
</li>
<li><p><strong>Send Success Response:</strong> Finally, we return a success response to the user, confirming that their password has been reset successfully.</p>
<pre><code class="lang-javascript"> res.status(<span class="hljs-number">200</span>).json({ <span class="hljs-attr">success</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">"Password reset successful"</span> });
</code></pre>
</li>
</ol>
<h4 id="heading-what-happens-next-5"><strong>What Happens Next?</strong></h4>
<p>Once the user’s password has been updated, they can log in using their new password.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>This guide provides a complete flow for implementing user authentication using MongoDB, Node.js, and JWT. You’ve learned how to:</p>
<ul>
<li><p>Set up MongoDB and create a user schema.</p>
</li>
<li><p>Implement password hashing and JWT authentication.</p>
</li>
<li><p>Handle email verification and password reset functionality.</p>
</li>
<li><p>Protect routes with JWT-based authentication middleware.</p>
</li>
</ul>
<p>By following this guide, you’ll have a solid foundation for building secure user authentication in your Node.js apps!</p>
]]></content:encoded></item></channel></rss>