Best way to implement mobile number and OTP login

I have seen this: https://docs.wappler.io/t/login-create-a-working-user-login-page/2855
And this: About OTP with Security Login Action Steps
And this: https://docs.wappler.io/t/applying-security-to-your-nodejs-pages/21682

I understand how to create a normal, traditional login process with Wappler. What if I want to customise it? For example, I want to build a mobile number and OTP based login, without any password at all.

The “Security Provider” setup and the “Security Login” step in Server Connect expect a password field. I could use the OTP field as the password field. But I have 2 OTP fields in my table, storing the last 2 OTPs sent, and I want to validate against either of them.

So, basically, I would like to control how to validate the credentials, using my own DB query, and then I would like Wappler to do the actual login / session creation / JWT creation / cookie setting process. How do I achieve this?

Update:

Using the OTP field as the “password” field of the security provider has a problem. On successful login, I make the otp field in the database blank. But every time I make a change to my code, the Node server restarts. And on the next request to the server, I see the following message in the web server logs:

server-connect:app Executing action step restrict +0ms
server-connect:auth Login with cookie: { username: '<mobile_num>', password: '662805' } +0ms
server-connect:router Serving templateView /login +186ms

Basically, it looks like the server is trying to re-authenticate the user with the OTP with which the user successfully logged in. And it fails, because the otp field is blank now. So, the user is taken to the login page.

I need a way to use the security provider without the “password” field of the security provider.

I haven’t actually done this but I think it should work:

  • Add a ‘otpPassword’ field to your users table and when creating a user, generate a UUID and store it there (ideally using Argon hashing)
  • Have a separate table to record OTP requests with userid (or username/mobile), expiry and otpString fields.

When the OTP is requested, created an entry with the userid (or username/mobile), a suitable expiry in the request and fill the otpString field with the password retrieved from the user table but encrypted with the OTP you sent.

To confirm the OTP retrieve the latest request for the userid/mobile where the expiry is greater than NOW and try decrypting the otpString with the code. If successful, you can use the resultant password in Security Provider login step as the password (which is then stored in the credentials cookie of the device to keep the user signed in). Once used, set the expiry to NOW or a date in the past so it can’t be used again

You could take it further and send a UUID in the API response that is stored in Local Storage of the device and send the OTP by mobile. The UUID and the OTP would be hashed together and stored in the otpString field so it becomes device specific

Thanks for this. I understand what you are saying. The core point here being that we need to generate a static password for every user and use that in the security provider. So, the actual “Security Login” step would be fed with this static password.

The actual OTP verification logic is custom anyway, and it can be done in a variety of ways, one of them being what you have suggested. In your solution, I like how the actual OTP is not stored anywhere.

1 Like