Authorizing context actions where? In each function, or the controller?

Ok, here’s a compromise option between AoP and functional.

defauth create_user(user_params) do
  User.changeset(%User{}, user_params) |> Repo.insert
end

This would get compiled to this:

  @spec create_user(User.t, map)
  def create_user(%User{}=user, user_params) do
    with :ok <- UserPolicy.authorize(:create_user, user, user_params) do
      User.changeset(%User{}, user_params) |> Repo.insert
    end
  end

That way, the controller and everyone else is forced to provide that user for authorization, but doesn’t hide the user parameter and obfuscate how things work. And the context method gets to have a single responsibility.