What goes in changeset params vs the struct

Anything from params can be user set. So you’re correct, don’t let the user set role to anything they typed into params.

In your specific example, I would create a function that uses the put_change function to set the role and transform the changeset using pipes.

changeset = 
  |> changeset(%User{}, params)
  |> set_user_role("admin")

Repo.insert! changeset

...

def set_user_role(changeset, role) do
  put_change(changeset, :role, role)
end