(From my Medium - Sep 29, 2020)
It’s been a little over a year since I wrote my previous post on how to take the first steps towards a startup. During this time, I managed to implement one project, which could not be launched due to COVID-19. I am soon planning to write a separate post about this project and the technical experiments that I made while working on it. Besides, I was starting another idea, which is now put on hold, and also several other ideas have appeared that one can start to implement. In fact, different ideas often come to my mind — small and not very. Probably, in the near future my main task will be to learn to think more “businesslike”. Because now all my ideas are just some things that are interesting to me either as a potential user or as a developer. That’s not the point, though.
The main thing that I have realized during all this time is that if there are so many ideas, then one of them can take off. But for that I need to learn to launch project after project very quickly. Sometimes I think: what is the problem, really? I have a lot of experience in the field of development, my own set of frameworks and tools that I feel comfortable working with. And now, in my thoughts, I have already gone full speed and implemented all the ideas that are written in my notebook. I almost got down to work for real, opened the IDE and then … just froze for a few seconds and then all the enthusiasm was gone. Guess what I was thinking? Yes, that’s right — authentication! In 90% of cases, the project requires auth. And it became a stumbling block for me. This routine issue precedes all the fascinating work that attracted me so much when I was thinking about working on a project.
Of course, you can implement the dev version of auth or even stub, and then write the real implementation. You can pull out the code and the database scheme from the previous project, then adjust it to the current realities and delete all the extra pieces. Which often seems more costly to me than writing from scratch. It is also possible to use third-party services, such as Auth0, which at first glance may seem extremely attractive. There is no need to develop authentication yourself, there is auth by login and password, as well as through social media.
However, I always have doubts about using external services, especially when it comes to such a critical part of the application as authentication. Auth0 offers 7,000 free users and unlimited logins. It’s great. Perhaps the application will not have so many users and it will be fine for a pilot run. But what if the number of users of the application exceeds this number, but the application still does not bring money. And most likely by that time you’ll be already paying for hosting and other services like mailing lists, monitoring systems, analytics. What if the same abstract Auth0 does not have the support of the social network you need, or you need to add some kind of business logic to the authentication process? In other words, such services can provide a significant speed boost at the start and provide a vendor lock-in in the future.
To sum it up, I have accumulated a lot of thoughts about different auth methods, their pros and cons. Therefore, I decided to organize all this in the article below and share my experience and advice. So, let’s get started.
Due to the fact that this is the oldest and most proven method, it is the most common. That’s right — you enter the username and the password — and here you go. Nowadays, you don’t have to think about how to pick a good salt to protect your password with double processing it with the md5 function to get a hash (shoutout to PHP). I believe, any language already has a 100 per cent proven and safe way to do it. There are still some nuances, though.
From the user side:
Users often come up with passwords that they are sure they will certainly not forget. But in the end, they constantly mess around with annoying forms of password recovery. And in case your resource has not proven its need for the user, they can quit this business halfway through.
So as not to forget passwords, users often have one for all occasions. However, most likely users don’t trust your resource at the initial stage. And the user will think ten times before risking the key to all his doors. With a high degree of probability, such a user will close an untrusted resource.
For obvious reasons resource developers frequently set up password strength rules (we’ll talk about it below). In case the user from paragraph 2 decided to set his password, it so often happens that security rules suggest adding a couple special characters or numbers to this password. In such cases some types of app users will close your app immediately (I was in this group of users too). But if a user decides to upgrade his password with a couple of new symbols, he risks falling into the group of users from paragraph 1.
A user might not remember if he has registered on this portal before or not. What to choose — registration or authentication? I can’t sign in because I don’t have an account or because of the wrong password? Screw that, I’ll just reset the password. Okay there is no link to reset my password, but … why? Is it because I wasn’t registered, or mail sending is taking too long or there are problems on service side?
A registration form often has custom fields on top of credential fields: name, sex, address etc. Having seen this a user, not being 100% sure they need this particular service, might just run away. Ideally a registration form shouldn’t have any extra fields. Any extra info can be requested when the time comes. For example, in e-commerce store you’d better not ask a customer for their address during the initial registration — he may never make an order — but wait right till checkout instead. For sure, there can be some exceptions. In case you need to show what services are available based on the user’s address. Anyway, if you need to have some extra data, I’d recommend to always do it in the second step. We first create an account that contains only credentials and then fill in the profile with other important info. Thus, we’ll decrease the probability of a user disappearing in step one. If however he’ll runaway in step two, we still have his email. Potentially we can bring such a user back. The main thing is not to be too aggressive or obsessive doing that.
User can face the biggest internet-spawned evil — captcha. This is a big separate story that we won’t dwell on here. Just try to make a list of your 10 most hateful things (about registration/authentication). I’m sure captcha will rank high on this chart.
On the dev side it’s simple — one has to do a huge amount of work.
Implementation of login and password input, their processing, output of clear error messages in the program interface. Saving the session in cookies or issuing a JWT token.
Cookies for storage is a fairly old mechanism that is gradually becoming a thing of the past and is being replaced by JWT tokens. This is also a large separate topic for discussion. Let me just say that JWT is very good. But it takes more time and effort to implement authentication through tokens, as well as understanding of how access tokens and refresh tokens work, what they are used for and so on.
You need to think about security of users and the service itself. Therefore, you’d better integrate (or write your own) solution to check the strength of the created passwords, and also correctly convey this information to the user through the interface. For greater security, perhaps you might notify the user that it is time for him to change the password, say, in 3 months? Or even demand a new password from him immediately after authentication by means of the expired password? Well, no — it’s too much!
To increase security, of course, you should implement captcha. At least display it after several unsuccessful authentication attempts (which in itself is additional work). What should you take? Google reCAPTCHA with its traffic lights and bridges or invisible mode that trusts you simply because you are logged in to Google services. Or curvy, hard-to-read self-made characters, which are considered incorrect even if everything is entered correctly, at the sight of which the user will close the tab or application? You need to think. Perhaps I will leave this question unanswered.
- The classic form of authentication/registration is rich in various flows. Separation of authentication and registration, functionality “forgot password”, “forgot login”, confirmation of the account by clicking the link received by email. All these things put a load on both interface development and the logic. It is necessary to add letter sending. But what should I put in the letter? A link to the new password form? A ready-made temporary password that will have to be changed in your personal account? I would choose the first option from a developer’s point of view since it is safer. And the second from the user’s point of view — it’s faster this way. Either way, these are the things you have to worry about and ultimately implement.
In my opinion, in comparison with the previous method, this option can be called ideal for the user. You enter your login, receive an email or a text with an access code. This solves almost all the difficulties a user encounters when working with classic authentication. And for a developer, in a sense, this method is easier to implement. At least, the developer does not need to think about the complexity of the password and the flow becomes very simple — due to the lack of separation of registration and authentication and the password recovery function. For me, these points are extremely significant and outweigh the concerns that this method adds. However, these conveniences have their own price… So, the cons.
From the user side:
If the user is not actively using email, then it is possible that he is not signed in in his email client. And if email does not play a role in his life at all, then there is a possibility that it will be so difficult for the user to remember his mail credential that he will not even try. A simpler case is also possible. For example, a user works with mail only on a computer, and tries to access your service from a phone. There is no computer at hand … Well, you understand. To be honest, I have no idea how both of these options are possible in real life, especially the first one. But all I want to say here is that this method essentially makes your service dependent on another service. Of course, you can prompt the user to log in with a phone number. The phone is more often at hand. However, the user will leave his phone number to an untrusted service only as a last resort. In general, I recommend using phone logins only if it makes sense. For example, you have a courier delivery service, and the courier needs your number for quick communication. Otherwise, both you and your users will suffer. So, offering the choice of either email or phone — yup, but forcing the phone option on them — big no-no.
For some reason, email or SMS may be delayed and, in some cases, delayed significantly, and sometimes not come at all. Of course, if everything works stably on the part of your service and mail providers, there should be no problems.
As for the developer:
To prevent emails with access codes from getting into spam, it is necessary to integrate with trusted message sending providers, such as: Mailchimp, Mailgun. If authentication is only done by email, then you have one provider. If authentication is done by email and phone, then you already have two. If you want to insure against a failure, then each of them should have fallback services, that is, there are already 4 integrations.
Partial inability to be responsible for the stability of your application due to the dependence of the critical part of the system (in the form of authentication) from third parties. Of course, any service is this way or another not a standalone solution and depends on something. But there are things that cannot be passed on to third parties, such as Internet access or hosting. And there are dependencies that you can avoid and reduce the likelihood of system failure. Especially when it comes to not the secondary functions of the service, but the primary ones.
Integration and guaranteeing stability are not all of your problems. The main problem here is the price. Whereas everything is more or less obvious with sending emails — there is a mailgun, which will cost $ 0.80 per 1000 messages, it is noticeably worse with sending text messages. With an average price of $ 0.05, you will have to pay $ 50 for the same amount! Which is completely overwhelming for launching a startup that is not yet generating income. If you know cheap or maybe even free services for sending email or SMS, please write in the comments.
To save money, you will have to add captcha before sending the message
If the user does not exist, authentication is performed using a one-time password. Further authentications are carried out in the same way. After the user has created a password, entering a one-time code is done as the second step if additional security is needed or this step is omitted if simplicity is required.
This method can be attractive in some cases, provided that you are absolutely certain that you need to have standard authentication via login and password. Let’s say, your application, logically speaking, cannot function at all without the user creating an account. But it would be illogical to load the user with unnecessary steps and thereby scare him away. You allow him to log in with a one-time password, thus creating a “draft” account — prospect (a marketing term describing a potential customer). By draft, I mean an incomplete account with which you can view resources, but you cannot perform some operations, such as ordering services or goods, posting articles or other materials, etc.
As soon as the user reaches the step that requires creation of a full-fledged account, the system will ask for a password. Thus, we did not lose potential users ahead of time and delayed the user’s torments as much as possible. As a result, we got a full-fledged, secure account, which is important if the application allows us to carry out financial transactions. If security is not so critical, you can allow the user to enable and disable two-factor authentication.
Since this method contains the functionality of the previous two approaches, it incorporates all the pros and cons of both.
And, of course, authentication using our favorite social media. The method is extremely interesting and attractive. But, unfortunately, with its own serious shortcomings. On the positive side — we completely save the user from almost all the problems listed earlier! If a user has an active account on a social media, he can easily use our resource and any other resources that support authentication through social media. As a bonus, the user gets the opportunity to manage their sessions through a centralized location. Has your phone or computer been stolen? Go to your social media account and close sessions in all related applications — your accounts are under reliable protection. Also, signing through social media eliminates the need to verify the account — social media itself does this. And this approach frees the developer from a huge amount of decision-making and work, which is worth a lot!
However, for some reason, applications that only use social media authentication represent tiny minority. It’s time to look at the flaws.
For the user:
What if the user does not use any social media? Yes, I have met people a couple of times claiming that they are not on any network. I am sure that in the modern world, if a person uses the Internet in principle, then most likely he will have some kind of account. At least a Google or Apple account from his smartphone. Some more people who avoid social media have nevertheless fake accounts for different purposes. But the main idea here is that in a rare case, you can lose a potential user due to the lack of an alternative authentication method.
Consider a completely opposite situation. I am an imaginary user who replaced real life with online one on a social media. I have all the social media that your application offers me for authentication. I can’t remember if I logged in to this service earlier or I just don’t remember what I used — Facebook, Instagram, Twitter… I clicked the wrong icon and got an empty account. Also, all applications implement sign in through a different set of networks. I would be happy to use everywhere, say, Twitter. This option is not always available, though. It would be convenient if the authentication method that was last used by the user was highlighted in the application interface. You can store this information in cookies or local storage. However, if you use the service from another device or even a browser, magic won’t work. So, this is only a partial solution to the problem. For me personally, this is the number one reason why, as a user, I rarely make a choice in favor of authentication via social media networks. I have not been able to work out an algorithm on how to choose a social media to sign in. Therefore, I usually just register with the service directly. Moreover, I have 1Password. But more on that at the end of the article.
And what kind of service is it, exactly? Can I trust it to access my imaginary Facebook account? Will the service abuse my trust and use my data for its own hidden purposes? There are several problems with understanding the “rules of the game.” First, a list of data that will be transferred from the social network, appears only after you click on its icon and the authentication window in an external resource has opened. Secondly, a correctly configured scope on the part of developers plays a huge role. Scope is a list of privileges that the application will ask for from a social network. Sometimes applications ask for too many privileges and it is not always clear whether this is really necessary. Maybe the developer just requested the full scope so as not to deal with this, maybe he even wanted to return to the question by the time of the first release but forgot. Or maybe the application has its own plan for user data. In any case, this looks just as suspicious as an application on the phone that requests access to the microphone, while it does not have audio/video recording functions or support for voice commands. Therefore, it seems to me that it would be nice to familiarize the user with what kind of data you intend to use and how. This is especially important if your application contains functionality that the user does not know about. Just one example of the top of my head: we use write permissions not to post ads on your wall, but to save photos from the application to your photo album.
Another small point about safety, but from a different angle. In the most innocent case, a service can display in the user profile a link to the social network through which he signed in. Which can be undesirable for a number of reasons. From a simple “I don’t want to” to a desire to separate different areas of your life.
Also, if the user is far from IT, it may not be clear to them what auth is and how it works. I am sure that there are still users who, seeing the offer to enter their email and password when signing in the application, mistakenly believe that it is actually their email account password that they are asked to input right now. And given the fact that users often have one password for all occasions… So, not every user understands that the password is entered on the side of the imaginary Facebook, and not in the application for which authentication is required. Therefore, not everyone wants to risk their only password.
For the developer:
You’ll have to create a developer account for each social media to get tokens and API keys. That’s not easy nowadays. For instance, to obtain Twitter API access it’s required to write a detailed explanation how your application intends to use the provided data. All app creation requests will be moderated manually by real people. In case a moderator gets any doubts, you’ll receive an email with extra questions. Each social media may have their own policies and requirements. That’s means to implement authentication through the number of social media you will have to spend time and make some effort.
If you are not going to use ready solutions like Passport.js or there are no similar packages for the platform you use to develop your app, you will have to read a lot of different documentation and integrate all those API’s in manual mode.
Different social media provide different user data. For example, some social media won’t give you a user email, which is necessary for your app. That’s why you can’t avoid implementing the second step to collect missing data.
Ugh, well, I am done with all the methods, pros and cons that I have come across in my experience. I told you everything I knew. Finally, of course, I would like to share my opinion on when to choose which method. At the end of the day, all these thoughts came to my mind in the process of thinking about how to quickly do auth in my future projects.
It seems to me that in the balance between usability and speed/ease of implementation, one-time password authentication wins. If you are developing MVP or PoC, you can even postpone integrations with mailing services until you start attracting real users. That is, at the stage of development and testing in a closed circle and demonstrating the application to investors, you can get by sending login codes through a standard function or a function from some third-party libraries, which I am sure exist in every programming language.
Of course, authentication only through social media can be a great option too. For example, if you know your target audience perfectly. So, Tinder, when it was just launched and for a long time after, had authentication only through Facebook. Even photos could only be uploaded to a profile from Facebook albums. A real startup approach! If you are making an app for developers, it will most likely be sufficient to support the login via GitHub. But if everything is not so obvious, then you will have to implement user authentication sign in via the top 5–7 social media networks. Even at the stage of closed beta testing or showing it to potential partners.
If you need a wide range of authentication methods at the very start and are not afraid to get a vendor lock-in, then things like Auth0 and Firebase Authentication are most likely exactly what you need.
What do you think about it? What problems do you see when creating auth for a project? Perhaps you know ways to easily solve all these problems, for example, an analogue of oAuth, only open source. With any thoughts on this topic, I am glad to welcome you in the comments.
P.S.: So, I mentioned 1Password. This is by no means an advertisement. It’s just that I’ve been using it for over a year now and highly recommend it to anyone who wants to end the password confusion while staying safe. I create different passwords using the built-in password generator and 1Password remembers everything for me. All I have to do is show my face for Windows Hello to allow 1Password to fill out the login form. And on a smartphone, I use a fingerprint. It’s incredibly convenient! If you don’t have biometrics on your device, then everything is the same for you — you only need to remember one password, from 1Password itself.