Jabed Zaman

Managing users for your SaaS

August 15, 2024 (4 months ago)
# authentication# authorization# users# saas# security

Lets agree on this one thing first, being a developer... INDIE developer, you must have been having lots of side projects which you started but never finished. And if you are one of those who actually finished a project and launched it, getting the three loyal signups (of which two were you yourself) still great work.

But anyways, while building a scalable SaaS application, the part where we all stumble upon is managing users. And by managing users, I mean managing their authentication, authorization, and security. Lets have a look at this in detail.

Its 2024, (as per the date of this post) and we have a lot of options available to manage users. We have services like Auth0, Firebase, AWS Cognito, and many more. But the question is, do you really need them? Well, it depends on your use case. If you want full control over your user data, you might want to build your own authentication system. But if you are building a small project and want to focus on the core features, you might want to use a third-party service. Although... 💀 I belong to that group of devs who build everything from scratch. (prob, someday I will start even building the language itself from scratch)

The traditional way

The traditional way of managing users is to have a database table for users, and store their email, password, and other details. But this is not secure. You should never store passwords in plain text. You should always hash them before storing them in the database. And when a user logs in, you should hash the password they entered and compare it with the hashed password in the database.

const bcrypt = require('bcrypt');
 
const password = 'password123';
const hashedPassword = bcrypt.hashSync(password, 10);
 
console.log(hashedPassword); // $2b$10$3QJ6
 
const isMatch = bcrypt.compareSync(password, hashedPassword);
 
console.log(isMatch); // true

Okay, lets see this was very basic. But what about the security of the passwords? You should always use a strong hashing algorithm like bcrypt. And you should also use a unique salt for each password. This makes it harder for attackers to crack the passwords.

But still inspite of all these, a password based authentication is a pain in the ass. Implementing things like password reset, forgot password, etc is really hectic. Also while querying the db we might expose the hash sometime by mistake.

Going Passwordless

This is the new era of dev, we have lots of solution like oauth, openid, etc. They provide a centralized auth for our users. Also there are things like totp, mfa, hardware keys, etc. These prevents the mess of having passwords. Cmon we all bad at remembering passwords 🤷

Having such methods setup makes things way more secure.

Tips

When you have a form for sending the user login otp to mail, hackers can keep trying multiple tries to somehow guess that which email is already registered or not... Cause in case when user is not there we will get a faster response when compare to case where a user is there and we have other business logic like sending otp, generating otp, etc running before sending the response.

To prevent this you can add a random fake promise to avoid this vulnerability

 const user = await this.prismaService.user.findUnique({
      where: { email, deleted_at: null },
    });
    if (!user) {
      /**
       * fake a time-consuming operation, and send a success message
       * to the user after the operation is done, this is just to
       * simulate a real-world scenario where the user is not told
       * if the email exists or not.
       */
      const randomTime = Math.floor(Math.random() * 5000);
      await new Promise((resolve) => setTimeout(resolve, randomTime));
      return { email: email, mail: 'sent' };
    }

Also, if you are implementing the traditional way, you can have two more columns in your user table, last_password_failed_at and password_failed_count. This will help you to track the failed login attempts and you can block the user after a certain number of failed attempts.

Make your users try setting up an authenticator app such as Google Authenticator, Authy, etc. This will add an extra layer of security to your application. And also prevents unncessary transactions cost for sending otps and even user can avoid the hassle of waiting for otps/cleaning the inbox.

Conclusion

In the end it all depends on your use case and your wish. Using third party services is great but let me remind you that you would be really dependent on them. If they go down, you go down. Vendor lock-in is a real thing let me tell you.

And building your own system is great but you have to take care of everything from security to scalability. So choose wisely.