# 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.