Start learning free

LESSON 87 OF 173 · BACKEND: USERS AND SECURITY

Log In in Go

Practice

Sign-up stores a hash of each password. Logging in is the other half: the user sends their email and password, and the shop checks them. It's a POST, so the password travels in the body, not in a URL that ends up in logs and in the browser's history.

Checking a password: you can't undo a hash, but you can hash the typed password again with the same salt and compare. checkPassword(passwordHash, password), already in your code, does that and gives true or false. For example, with another password:

stored := hashPassword("tulip7")
fmt.Println(checkPassword(stored, "tulip7"))   // true
fmt.Println(checkPassword(stored, "tulip8"))   // false

When the email has no account or the password is wrong, answer 401 with one vague message for both. Two different messages would let anyone find out which emails have an account. After two sign-ups, the test requests get:

POST /register  {"email": "ana@example.com", "password": "secret123"}  →  201  {"email": "ana@example.com", "id": 1}
POST /register  {"email": "ben@example.com", "password": "tea4two"}    →  201  {"email": "ben@example.com", "id": 2}
POST /login  {"email": "ana@example.com", "password": "secret123"}     →  200  {"email": "ana@example.com", "id": 1}
POST /login  {"email": "ana@example.com", "password": "secret999"}     →  401  {"error": "Wrong email or password"}
POST /login  {"email": "nobody@example.com", "password": "secret123"}  →  401  {"error": "Wrong email or password"}
POST /login  {"email": "ben@example.com", "password": "secret123"}     →  401  {"error": "Wrong email or password"}
POST /login  {"email": "ben@example.com", "password": "tea4two"}       →  200  {"email": "ben@example.com", "id": 2}

Your task: add a POST /login handler. Read the user's row by email into id, email and passwordHash, answer {"error": "Wrong email or password"} with 401 when there is no such row or the password doesn't match the stored hash, and otherwise answer the user's "id" and "email" with 200.


Assignment
Follow the Coding Tutorial to build the POST /login handler.


Hint
Test err == sql.ErrNoRows first and join the two failures with ||: when the first part is true, Go never calls checkPassword. Put a return after the 401, so a failed login never reaches the 200 answer.


STEP 1 OF 8
    Ctrl + Enter to check

    Auth Login in Go

    Keep going with Go1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free