Start learning free

LESSON 99 OF 173 · BACKEND: USERS AND SECURITY

Don't Let Clients Set Everything in Go

Practice

A sign-up sends a JSON body, and a client can put any keys in it, not only the ones your form asks for. If your code saves every key as a column, the client chooses what gets stored: "role": "admin" makes an admin, and "id": 1 tries to take the admin's id. This hole is called mass assignment.

The fix is an allowlist: a list of the keys a client may set. You build the new row yourself and copy only the keys on your list. Everything else in the body is ignored. Here is the idea for a review form:

var reviewFields = []string{"stars", "text"}

review := map[string]any{}
for _, field := range reviewFields {
	value, ok := data[field]
	if ok {
		review[field] = value
	}
}

The starting code has a helper, insertRow(table, row), that saves a map as a new row, and a Profile type with the columns a client may see. Answer with what the database stored, not with what the client sent. Ana asks to be an admin and becomes a customer. Ben asks for id 50 and gets the next free id:

POST /register  {"email": "ana@example.com", "password": "secret123", "name": "Ana Pop", "city": "Cluj", "role": "admin", "id": 1}
  →  201  {"city": "Cluj", "email": "ana@example.com", "id": 2, "name": "Ana Pop", "role": "customer"}
POST /register  {"email": "ben@example.com", "password": "tea4two!", "id": 50, "role": "admin"}
  →  201  {"city": null, "email": "ben@example.com", "id": 3, "name": null, "role": "customer"}
POST /login  {"email": "ana@example.com", "password": "secret123"}
  →  200  {"token": "<token>"}
GET /me  (Authorization: Bearer <token>)
  →  200  {"email": "ana@example.com", "id": 2, "role": "customer"}
POST /products  {"name": "Desk", "price": 120}  (Ana's token)
  →  403  {"error": "Admins only"}

Your task: add the columns name and city to the users table and write the allowlist signupFields. In the POST /register handler, build newUser from that list, add the password's hash, save it with insertRow, read the stored row back into a Profile, and answer it with 201.


Assignment
Follow the Coding Tutorial to close the mass assignment hole in POST /register with an allowlist.


Hint
Range over signupFields, not over data: then the loop never even meets "role" or "id". value, ok := data[field] tells you whether the client sent the field, so a missing name simply stays NULL, and the Profile's *string shows it as null.


STEP 1 OF 12
    Ctrl + Enter to check

    Sec Mass Assignment 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