<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Faizan Pasha</title>
    <description>The latest articles on DEV Community by Faizan Pasha (@faizanpasha).</description>
    <link>https://dev.to/faizanpasha</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F927087%2F94a1e277-278a-4942-aa9a-675f05c0d159.jpeg</url>
      <title>DEV Community: Faizan Pasha</title>
      <link>https://dev.to/faizanpasha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/faizanpasha"/>
    <language>en</language>
    <item>
      <title>Phone Auth with Express and Node.js</title>
      <dc:creator>Faizan Pasha</dc:creator>
      <pubDate>Sun, 02 Oct 2022 02:56:50 +0000</pubDate>
      <link>https://dev.to/faizanpasha/phone-auth-with-express-and-nodejs-490m</link>
      <guid>https://dev.to/faizanpasha/phone-auth-with-express-and-nodejs-490m</guid>
      <description>&lt;p&gt;A simple web tutorial to make a Phone Auth API with express using node.&lt;br&gt;
Sign In user with Phone Number and OTP without Firebase or AWS Amplify.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm using Twilio in this example you could use any SMS provider.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Dependencies needed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Twilio&lt;/p&gt;

&lt;p&gt;call the API to send the OTP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Crypto&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create a hash using &lt;code&gt;sha265&lt;/code&gt; for client identification.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;jsonwebtoken&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To send a &lt;code&gt;JWT Token&lt;/code&gt; when the user is authenticated.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bodyParser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To parse the request body&lt;/p&gt;
&lt;h4&gt;
  
  
  Installing the dependencies
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install Twilio crypto jsonwebtoken bodyParser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;Import statements&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let app = require('express')();
let crypto = require('crypto');
let jwt = require('jsonwebtoken');
let bodyParser = require('body-parser');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A fake database for demo purpose, Make sure to connect it to a real database later&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var users = [
    {
        id: 1,
        name: 'John Doe',
        number: '+1234567890',
    },
    {
        id: 2,
        name: 'Bob Williams',
        number: '1234567891',
    },
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Body parsing was bundled in &lt;code&gt;express&lt;/code&gt; by default from &lt;code&gt;v-4.16.0&lt;/code&gt;. since 2020 &lt;code&gt;express&lt;/code&gt; has removed default body parsing. We have to do it manually now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let jsonParser = bodyParser.json();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generating keys
&lt;/h4&gt;

&lt;p&gt;Generate a &lt;code&gt;JWT Key&lt;/code&gt; and &lt;code&gt;Hash key&lt;/code&gt; to verify that the token sent by the client has not been tampered with.&lt;br&gt;
There are a lot of ways to generate unique keys. I am using &lt;code&gt;node&lt;/code&gt; to generate unique keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('crypto').randomBytes(64).toStrong('hex')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will generate a random string. Copy it and paste it into the .env.&lt;/p&gt;

&lt;p&gt;Run this command again for the second key and paste it into the .env.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HASH_KEY=&amp;lt;YOUR_HASH_KEY_HERE&amp;gt;
JWT_KEY=&amp;lt;YOUR_JWT_KEY_HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setup Twilio
&lt;/h4&gt;

&lt;p&gt;For the sake of this example, we’ll be using Twilio but the concepts and code examples remain true for all SMS providers out there.&lt;/p&gt;

&lt;p&gt;Login to your Twilio console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1664675431123%2FDUGxSEKbb.png%2520align%3D" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1664675431123%2FDUGxSEKbb.png%2520align%3D" alt="Screenshot 2022-09-22 at 5.13.24 PM.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the &lt;code&gt;Account SID&lt;/code&gt;, &lt;code&gt;Auth Token&lt;/code&gt;, and &lt;code&gt;My Twilio phone number&lt;/code&gt; from the dashboard.&lt;br&gt;
Paste it in &lt;code&gt;.env&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TWILIO_ACCOUNT_SID=&amp;lt;YOUR_ACCOUNT_SID_HERE&amp;gt;
TWILIO_AUTH_TOKEN=&amp;lt;YOUR_AUTH_TOKEN_HERE&amp;gt;
TWILIO_NUMBER=&amp;lt;YOUR_PHONE_NUMBER_HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Declare the .env variables
&lt;/h4&gt;

&lt;p&gt;Declare the .env variables on top of the file to get the secret key from the .env variable&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require('dotenv').config();
let hashKey = process.env.HASH_KEY;
let jwtKey = process.env.JWT_KEY;
var accountSid = process.env.TWILIO_ACCOUNT_SID;
var authToken = process.env.TWILIO_AUTH_TOKEN;
let twilioNumber = process.env.TWILIO_NUMBER;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declare the &lt;code&gt;Twilio&lt;/code&gt; client your &lt;code&gt;Account SID&lt;/code&gt;, &lt;code&gt;Auth Token&lt;/code&gt;, and &lt;code&gt;My Twilio phone number&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var client = require('twilio')(&amp;lt;Auccount SID&amp;gt;, &amp;lt;Auth Token&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Now we are ready to build the endpoints.
&lt;/h4&gt;

&lt;p&gt;We have to build two endpoints&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request OTP &lt;/li&gt;
&lt;li&gt;Verify OTP&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Request OTP
&lt;/h3&gt;

&lt;p&gt;Get the user number from the request body&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let number = req.body.number;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OTP generation logic&lt;br&gt;
It will return 4 digit OTP, If you want to increase the length increase a &lt;code&gt;0&lt;/code&gt; of &lt;code&gt;1000&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let otp = Math.floor(1000 + Math.random() * 9000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a secret hash to verify the client in &lt;code&gt;2. Verify OTP&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let ttl = 5 * 60 * 1000;
    let expires = Date.now() + ttl;
    let data = `${number}.${otp}.${expires}`;
    let hash = crypto.createHmac('sha256', hashKey).update(data).digest('hex');
    let secretHash = `${hash}.${expires}`;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check whether the user number is already registered&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var user = users.find((user) =&amp;gt; user.number === number);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Handle the case if the user doesn't exist&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    if (!user) {
        users.push({
            id: users.length + 1,
            name: '',
            number: number,
        });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the fun part. Sending the OTP through Twilio and &lt;code&gt;secretHash&lt;/code&gt; through &lt;code&gt;response&lt;/code&gt;.&lt;br&gt;
Twilio might get some errors so it is an excellent practice to wrap it inside of &lt;code&gt;try catch&lt;/code&gt;. call the &lt;code&gt;client&lt;/code&gt; method from Twilio and send OTP through SMS.&lt;br&gt;
The &lt;code&gt;body&lt;/code&gt; property takes the message you want to send the client.&lt;br&gt;
&lt;code&gt;from&lt;/code&gt; property takes your Twilio phone number.&lt;br&gt;
&lt;code&gt;to&lt;/code&gt; property takes the client's number.&lt;/p&gt;

&lt;p&gt;if the message is sent successfully, send the &lt;code&gt;secretHast&lt;/code&gt; through &lt;code&gt;response&lt;/code&gt;. If &lt;code&gt;Twilio&lt;/code&gt; throughs &lt;code&gt;error&lt;/code&gt; send &lt;code&gt;"Error sending OTP"&lt;/code&gt; as &lt;code&gt;response&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;try {
        client.messages
            .create({
                body: `Dear customer,\n Your OTP is ${otp}. PLEASE DO NOT SHARE THIS OTP WITH ANYONE.`,
                from: twilioNumber,
                to: number,
            })
            .then(() =&amp;gt; {
                //Send the secret hash to the client
                res.json(secretHash);
            })
            .catch((err) =&amp;gt; {
                //Handle the twilio error
                res.status(500).send('Error sending OTP');
            });
    } catch (err) {
        //Handle the error
        console.log(err);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Verify OTP
&lt;/h3&gt;

&lt;p&gt;Get &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;OTP&lt;/code&gt;, &lt;code&gt;secretHash&lt;/code&gt; from the requesr body&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let { number, otp, secretHash } = req.body;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Slice the hash and the expiry time from the secretHash sent to the client in &lt;code&gt;1. Request OTP&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let [hashValue, expires] = secretHash.split('.');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check if the has expired and handle the case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let now = Date.now();

    if (now &amp;gt; parseInt(expires))
        return res.json({ error: 'Timeout. Please try again' });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new hash using the user number, OTP, and the expiry time&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    let data = `${number}.${otp}.${expires}`;
    let newCalculatedHash = crypto
        .createHmac('sha256', hashKey)
        .update(data)
        .digest('hex');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the new hash with the hash sent by the client. if they match then generate a &lt;code&gt;JWT&lt;/code&gt; with the user information from the database and add an expiry period.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    if (newCalculatedHash === hashValue) {
        var user = users.find((user) =&amp;gt; user.number === number);

        let payload = {
            number: number,
            name: user.name,
            id: user._id,
        };
        //Create a JWT token
        let token = jwt.sign(payload, jwtKey, { expiresIn: '1y' });

        //Send the token to the client
        return res.json(token);
    } else {
        //Handle the case when the hash does not match
        return res.json({ error: 'Invalid OTP. Please try again' });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once complete, we’re all ready to preview the project. Run the following command to run a local development server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node index.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Source code is available at &lt;a href="https://github.com/Faizan-Pasha/express-phone-auth-example.git" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
