We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Error Responses

In general, we want to inform our application's users when something goes wrong.

if err := db.ValidateUser(r.Context(), username, password); err != nil {
	httpError(r.Context(), 401, err)
}

This might seem reasonable. But we don't know (at least from this code alone) what the error contains. In the worst case, it may include the username and password. Yikes!

user "bob" unable to log in with password "OpenSesame"

That would obviously be bad. Here's another (and perhaps more realistic) possibility:

sql: no rows in result set

That seems safe, right? No password, no username... but not so fast!

The requester knows which username they sent. If they get this message, they can infer that the username doesn't exist. That's an information leak. An attacker can probe many usernames to discover valid accounts.

A safer approach is to always return a generic "unauthorized" message, regardless of the reason (missing user, bad password, disabled account, and so on).

Consider another subtle example:

table `migrated_users` does not exist

This might happen after a schema change if we forget to update the validation query. It also exposes internal architecture to the caller. Maybe those details aren't exploitable, maybe they are; we usually don't know in advance. Either way, that message is useful to developers, not end users.

There are other times when you'll want to add explicit debugging information to your errors, and you probably don't want that information leaking to your users.

These are all cases where you should log full details but return a safer message to the user.

Assignment

Return safer HTTP error messages without losing diagnostic logs.

Restart your server with LINKO_LOG_FILE=linko.access.log set:

LINKO_LOG_FILE=linko.access.log go run .

Run and submit the CLI tests from the root of the Linko repo.