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:
REVIEW_FIELDS = ["stars", "text"]
review = {}
for field in REVIEW_FIELDS:
if field in data:
review[field] = data[field]
Then 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 SIGNUP_FIELDS. In register, build new_user from that list, add the password's hash, save it with insert_row, and answer the stored row with 201.
Assignment
Follow the Coding Tutorial to close the mass assignment hole in POST /register with an allowlist.
Hint
Loop over SIGNUP_FIELDS, not over data: then the loop never even meets "role" or "id". Copy a field only if field in data, so a missing name simply stays empty.
Free plan: 30 tutor messages. PRO is unlimited.
