# auth.validate-login
Checks a login form before the API looks anything up, and answers in the
shape an API's `validation_failed` error and a form both want:
```
validateLogin(" Ada@Example.COM ", "correct horse battery staple")
# {valid: true, email: "Ada@example.com", fields: {}}
validateLogin("ada@localhost", "")
# {valid: false, email: null,
# fields: {"email": "Enter a valid email address, like name@example.com.",
# "password": "Enter your password."}}
```
When `valid` is true, look the account up by `email` from the result: it has
been through `auth.normalise-email` (trimmed, domain lower-cased), exactly as
`auth.validate-registration` stored it, so `Ada@EXAMPLE.com` finds the
account `Ada@example.com` made. Throttle on that normalised email too
(`auth.login-throttle`), so changing the domain's case does not dodge the
count.
**email**: empty after trimming ASCII whitespace is "Enter your email
address."; anything else `auth.normalise-email` refuses is "Enter a valid
email address, like name@example.com.", the same messages sign-up uses.
**password**: only its presence is checked, "Enter your password." when it
is empty. It is deliberately not trimmed (a space can be part of a password)
and never checked against a password policy: a password set under an older,
weaker policy must still log in, and a login form that says "use at least 15
characters" tells an attacker what the policy is while telling the user
nothing useful. Whether it is right is `auth.password-hash`'s
`verifyPassword`, after the throttle allows the attempt.
`fields` lists only the fields that need fixing, keyed `email` then
`password`. A value that is not a string (a JSON body with a number where
the password goes) is treated as empty, so a malformed request gets field
messages rather than an exception. It never throws.