It goes without saying that good login and registration forms are essential to providing a great user experience.

However, more often than not, various implementations trade-off good UX for security assumptions that are out of place.

Let's take a look at 3 easy steps to improve your authentication UX and comment on how to tweak the defaults set in Devise, the most popular out-of-the-box authentication solution in Rails.

Get rid of the ambiguous login failure message

Usually, login forms show the same error message upon a failed login attempt, regardless of whether you've mistyped the email or the password:

Invalid email address/password combination.

I’ve personally changed multiple emails through the last couple of years so sometimes I don’t know which email I’ve used on a certain service (mostly on services I haven’t used for some time or don’t have them in my LastPass vault yet). The process of getting the right email and password combination can get downright irritating, so oftentimes I resort to trying to send myself a password reset email to the right email address.

A better approach for websites would be to say which of the two is actually wrong:

An account with the given email address does not exist.

The given password mismatches the one stored for that particular user.

If the security skeptic inside you now thinks this is a obvious security issue since the internet villains could easily find out which emails are in use and which are not, you’re somewhat wrong:

You probably have a user registration form, so it's really easy to find out if an email is in use by trying to register with that email address.

If you still think that this approach is wrong, some of the best-known sites in the world use it - check out how Google, Netflix, Facebook, Pinterest or Eventbrite handle invalid login attempts.

Devise Implementation

Devise hands out an easy way to tweak these messages with the I18n internationalization and localization framework, and it’s a configurable YAML file:

en : devise : failure : not_found_in_database : We couldn’t find an account for that email address. invalid : Sorry, your password was incorrect. Please double-check your password.

It’s good practice to link back to the registration form after an unsuccessful login occurs due to the email not existing in the database.

Ditch the password confirmation field

Your user conversion rate is proportional to the simplicity of your registration form. Some of the simplest registration forms (excluding social logins with Facebook, Twitter, etc.) only contain three fields: an email, password, and a password confirmation field.

Can it get any simpler than that? Sure it can, ditch the password confirmation.

When was the last time your password and password confirmation field mismatched? I think I never actually got that error. And if your users manage to mistype their password, it’s easy for them to reset their password since Devise offers that functionality out-of-the-box.

Devise Implementation

This one’s even easier to accomplish - just remove the password confirmation field from your HTML form ( views/devise/registration/new.html.erb ) and Devise will automatically ignore it since it’s nil (unlike when you submit a blank confirmation field through the form, then it’s an empty string).

Show if the email exists when resetting your user's passwords

Regardless of whether the email address exists or not, some websites show the same message after requesting a password reset:

An email with a password reset link has been sent to you.

The security implication behind this ambiguous message is that we don't want to show nosy people whether an email is used on our website or not. The reason to ditch this behavior is the same as before - people can still use the registration form to find which emails were already used.

Devise Implementation

By default, Devise shows whether the email address exists or not, so there's nothing to do here.

Important Note

Showing whether an email address exists on login and forgot password forms isn't a security risk if you have a registration form showing the exact same thing. However, you might have an invitation-based system and no registration form. In that case, you're not exposing the user's email, so the same security assumption doesn't imply.

Conclusion

If you want to prevent malicious attacks, don't try doing it through ambiguous error messages. Instead, use 2FA (devise-two-factor) or throttle your requests with Rack Attack.

These are obviously three easy wins, if you've got any similar ones up your sleeve, feel free to share your comments below.