Authentication for web apps is a difficult problem. Anyone who’s ever tried to create their own authentication system will tell you that there are a lot of unexpected edge cases. What’s more, your authentication system is an externally-facing part of your application. This means if someone is trying to hack into your application, your login system’s security will be one of the first places they check. There’s good news, though. If you’re using Rails to build your application, you can use Devise, a gem which is designed to make authentication easy. Fortunately, Devise has been used in production applications for years. It’s known to be secure.
If you’re just starting to use Rails Devise to authenticate your Rails apps, you might have some questions about the best ways to do it. That’s what this article is for. We’ll walk through a number of tools that work with Devise to make sure your authentication has everything you need. So, what should you do if you need to add Devise to your app? Here are my top suggestions.
While a lot of applications today are still content to use a username and password combination for authentication, that creates problems. The more passwords you require your users to remember, the more likely it is that they’ll keep them in post-it notes on their monitor. Those habits harm the security of your app. What can you do to stop your users from writing passwords for your site on a post-it? Don’t make them remember a password! One of the best ways to do this is by authenticating through the OAuth 2.0 standard. You can use a centralized authentication system to verify your users’ identity, instead of making them remember yet another password.
Devise has a terrific plugin for adding OAuth: OmniAuth. OmniAuth provides you with all the tools you need to add an OAuth function straight into your existing Devise app. The great news is, it’s easy to plug in, even if you already have a standard Devise installation running in production. OmniAuth is terrific for authenticating both normal web applications as well as API back ends. Many of the other tools in this post can be ignored altogether if you have a good OmniAuth installation going.
A word of warning, though: OmniAuth is a little more difficult to set up than Devise itself. It requires more manual work, whereas Devise is pretty much automatic. If you’re planning on adding OmniAuth to your application, make sure to set aside some extra time to finish your integration. It’s not likely something you’ll do in an afternoon.
If you’re writing a brand new web application, you should use BCrypt to hash your passwords. But what if your application is being built on top of an existing database? You can’t just invalidate thousands or millions of passwords because you’re using Devise now. That’s a terrible experience for your users. That’s where the Encryptable plugin comes in. Encryptable allows for using alternative password hashing functions like AES or SHA. While neither of those are as good a choice for a new application as BCrypt, many legacy applications use them. Encryptable is a simple plug in to an existing Devise application, and once it’s up and running you don’t usually need to think about it again.
Again, if you’re making a new app, just use Devise’s default of BCrypt. But if you need to support older hashing algorithms, this is the right way to do it.
A strong username and password isn’t enough to secure an important user account. Over a long enough timeline, anyone can brute-force a password with enough computing power. This is why many applications and websites require users to change their passwords every few months. Devise Security is a plugin which adds this functionality to Devise. Like Encryptable, this is a plug-and-play plugin that requires very little work to add to your application. This plugin also enables storing a user’s password history in an encrypted form. When a user changes a password, your application can check to make sure it’s not one of their recently used passwords. If you require users to change their password every 90 days but they can reuse their last password, you’re not actually making their account more secure.
Before you charge off and add password expiration to your application, you should think about what you’re securing. Password expiration is a pretty annoying feature for most users. If your application doesn’t store sensitive user data, you probably don’t need a feature like password expiration. If your application is storing medical or financial data, you should make sure that your password policies are secure and well-enforced.
Another key feature in the war against account compromise is two-factor authentication (2FA). 2FA means that even if your user’s password is compromised, their account is still secure. 2FA systems like Authy, Google Authenticator or a YubiKey make 2FA accessible to even the least tech-savvy users. Much like password history checks, you should spend some time thinking about whether or not you need 2FA for your app before you roll it out. Adding 2FA for Devise is simple with the Houdini plugin. Like with OmniAuth, Houdini is a bit more manual work to set up and get working. You’ll need to modify your login forms to add fields for 2FA values, and configure your app to work with different supported 2FA applications.
That work is worth it, though. 2FA is one of the best ways to secure your user’s accounts.
When a user signs up for your application, you need to verify their email address. If you don’t, the consequences for your business are often dire. Validating an email before finishing account creation means that you know the user signing up has access to the email they claim to be using. That means you can securely use that user’s email address for account communication and crucial features like password resets. The good news is, Devise has this functionality built right into the gem. It’ll only take you a couple of hours to add email validation to your user models.
Unlike our previous couple of options, this is something you should absolutely turn on in Devise. Unless you’re using OAuth exclusively, email verification will save your application full days in user support time down the road.
Users choose bad passwords. It’s an unfortunate fact of life. Malicious actors figure out those passwords, and when they try to crack a new application, bad passwords are the first thing that they try. Many companies try to mitigate this fact by forcing complicated password requirements on users. We’ve all felt the pain of a login form which requires that you enter upper-case and lower-case letters, special symbols, numbers, your fingerprints, at least four emoji, and a hair sample. Like we’ve noted before: the more password requirements you put on your users, the more likely they are to just write it on a post-it note. Instead of asking users to come up with a convoluted password, enforce password security by checking whether a password has already leaked.
You can do this using Have I Been Pwned. The PwnedPassword extension for Devise makes this simple. Once it’s set up, it’ll check your user’s password on signup to make sure it’s not part of the known-bad password database. This will eliminate almost all simple and common passwords, meaning your users will have to be more creative. While that creativity has downsides (I can’t stress the post-it note thing enough), requiring your users to enter a password that isn’t known to be compromised is a strong step for account security. If you can’t use OAuth, this is a good step toward better security.
None of the suggestions here are silver bullets for securing your system. But they’re good steps to take. Devise is a great, easy-to-use authentication system, but it’s not perfect out-of-the-box. It’s a good idea to spend some time evaluating your authentication requirements while you design your authentication system, and see what else you need from Devise beyond its standard functions. If you do, you’ll build a more secure system. That secure system will boost your users’ trust and cut back on your support costs. I’ve used a lot of authentication systems for web applications before, and to me, Devise is the best on the market. It just takes a little bit of extra work to make sure that you’re setting it up in the best way possible.
Once you’ve got Devise ready to go, you should make sure you’ve plugged your application into a quality monitoring tool like Stackify’s Retrace. Even the best deployments are going to have bugs and scaling issues. If you can identify them quickly, you’ll keep yourself on the path of making sure your software is the best it can be.