Wouter Smet

On web startups, technology, music and growth

In A Perfect World, This Is How Web Sites Would Handle Login Forms

Ok, so you own a web site with users. Here’s what you typically do with your login form, where you ask e-mail (or perhaps nickname) and password.

You do some kind of query in your database if there is a user with that email + password combo, and if you found something, you log that user in. So something like:

SELECT * FROM users WHERE email=:email AND passwordhash=:passwordhash

So far so good, and bonus points for you if indeed you do not store passwords in plaintext and even more if you use a salt with that hash. Most companies get at least the no-plaintext part right these days I think. Good.

BUT, what if that query returns nothing? Here is what 99% of web sites do, including big ones like Twitter:

Screen Shot 2014-03-20 at 13.19.00

What GOOD sites do when no user/pass combination is found in the database, is a second query, to determine whether it was just the password that was incorrect, or perhaps the email does not exist in the database. As so often, Facebook gets this right because they are pretty good with the whole UI thingie:

Screen Shot 2014-03-20 at 13.21.42

This does not impose that much of an extra load on your server because the extra work is only done when somebody gives a wrong email/pass combo, so this would not double your queries on your user database or anything.

That’s all, thank you for listening. I’d love it if you share this post if you have been annoyed by this as well, or comment on it if you think I’m completely wrong in having this as one of my (many) pet peeves.

P.S.: I know there are arguments that can be made against revealing that a certain email address corresponds to a user. For example, perhaps it potentially gives people with malicious intents a (cumbersome) way to tell that an email address exists or that a given person is on a site.

And perhaps Facebook can get away with this because everybody and there their mother is on it, but perhaps you feel your Defense NASA Banking site cannot. Still, I don’t think most sites thought this far, and just go with the lazy route because everybody else does it so they get away with it. And at the very least, you have measures to prevent automated non-humans from submitting your login form I’m sure.

UPDATE: many people pointed out to me that the afterthought I so casually put inside a post scriptum is quite an important one. Maybe, to not give any information to hackers, here is an approach that is a bit more secure. Store the user’s email address in a cookie (even if you don’t have a ‘remember me’ cookie login, in which case all of this is obsolete of course), and if the email address he tried to log in with matches that cookie, then show him that the address exists but the password is wrong.

14 thoughts on “In A Perfect World, This Is How Web Sites Would Handle Login Forms”

  1. Wingi

    What about: “SELECT pwhash FROM users WHERE email=:email ”

    Hoping your PK of users is “email”, you can manually check if pwhash is the requested value and you dont need a second request to the database.


  2. Anonymous

    There is no need to do a second query.

    user = db.query(“SELECT * FROM users WHERE email=:email”)
    if (user.passwordhash == passwordhash):



  3. Sushant Athley

    Well I don’t think this is the best idea.
    What if your wife wanted to know if you were a member on a naughty site.
    She would enter your email address and any random password and know instantly whether you have a account with them or not.


  4. Kyle Jones

    I might be wrong, but I was under the impression that the first example is the better way to do it. The reason being that by not telling the user what part of the information was wrong you limit the amount of information given to a potential attacker. For example, if an attacker tries to log into a site and receives something saying the username was wrong, they then know that the password is correct, and vice versa.

    The user usually knows which one they are having trouble with, so you just provide links for recovering the username or password.


  5. Ricardo

    Actually, i learned somewhere that some sites don’t want to confirm that a user exists in their databases. Imagine an adult website, where you can login using your email + password. If someone want to check if another user is registered to this adult site, they just need to input an valid email with an invalid password. If the system just asks for the password, you now know that specific e-mail is an registered user to that specific service, which may be embarrassing for some users.

    And gratz for this nice blog!



  6. Stryder

    And those P.S. arguments are pretty good ones I think. Why should anyone even know that a particular email address has been registered to a site? That alone could allow a malicious user the ability to better socially engineer a profile of a person. Write a scraper, check 1,000 sites and see which ones a user has been too…That sort of automation isn’t something any site can really prevent short of requiring a captcha on first login.

    Regardless of whether most sites are ‘lazy’ about it or not, it’s definitely an area where learned convention serves us better.


  7. Jan

    What Facebook does here is fundamentaly wrong. Not from a usability perspective, but from a security one. Privacy is the keyword here. In a net where it practically became a de facto standard to use my email as username it is pretty easy for a social attacker to find out my email. Do I want this attacker to find out, whether I use service XYZ? No! I do not. Facebook gives a shit on privacy. But if you as a developer do, you are doing it wrong. Besides that it is much easier to hack an account, where one of two tokens in a two factor authentication scheme is already known. IMHO in that very case security and privacy should be more im


Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>