I have created many web applications that uses OTP verification via SMS. It works by sending a 4 to 6 digit number to the user's phone number via SMS. And the user has to enter the OTP in order to verify the phone number.
In most of the cases this is done using a simple technique, by keeping the OTP in the database or memory storage and matching it with the user input. In this article, I will try to explain how we can achieve the same result without any database of sorts.
But before we start: let's talk about the motivation behind this approach. Database operation is expensive, usually slower and because it relies on another application or service, has a probability to fail. Another good reasons is, OTP is a temporary data. It does not belong to the database.
Also, If you are developing a serverless Application. OTP verification can be done with a serverless function that does not depends on anything else.
This is now also available as NPM package
I will create an application that sends an OTP to the user using a SMS provider. I will not cover the code involved to send SMS, because that varies from provider to provider. Instead, I will only focus on the verification code. The language of choice is JavaScript, but the code should be simple enough to translate to any other programming language without breaking a sweat.
The Basic Idea:
The technique involves cryptography, in a sense It's quite similar to how JWT tokens are verified. But also very different from JWT because of the way data is handled. This technique is done using the following steps:
1. Create a cryptographic hash of the phone number, the generated OTP and the expiry timestamp combined.
2. Append the expiry timestamp with the hash and Send the hash to the user as the response of the first request.
3. Once the user gets the SMS, the user sends back the hash, the phone number and the OTP in the second request.
4. The server verifies the OTP by hashing the phone number, OTP sent by the user, and the expiry timestamp that was appended with the hash, the user sent back. Using the same key and same algorithm.
5. If the expiry timestamp is valid and still in the future. And the newly generated hash matches the one sent by the user. Then the OTP is authentic.
Lot to take in? Let's see it in Action. We will create two functions, one for creating the hash and and sending the SMS OTP, another for verifying the OTP.
We will use the awesome node package otp-generator to generate OTP codes in NodeJS. you need to install this package using npm or yarn.I've also omitted the package.json file in the example. Let's take a look at the hash generator code, every line is commented so that they are easy to understand:
This function will return a hash. The hash needs to be sent back to the user as HTTP response. when the user requests for an OTP. the sendSMS
function, which is a dummy function in this example. In the real world needs to be implemented depending on the vendor's API. This function will send the SMS to the user with the OTP.
The user, once received the OTP, will send the hash that came from the first request, phone number and OTP to the server and the below function will verify it. Let's take a look at the source code:
This method uses the SHA256
hashing (HMAC) mechanism to ensure data integrity and is almost always faster and more efficient than a database based OTP verification system.
This does not take into account stuffs like: error handling, http framework or routing etc. just to avoid unnecessary noise.
The full sample source code is available From this link
(Article needs review)