If this is related to comments I made in the RBAC thread, Iāll clarify a bit here.
I donāt think so, but you have me interested
I agree with this. What I was warning about was making all business logic authorization logic. That is to say, itās reasonable to ask āis this user authorized to create a userā. Itās also reasonable to say āIs it valid to create a user with no username? Noā. But itād be weird to say āYou are authorized to create a user with a valid user name, and not authorized to create a user without a usernameā.
All of it is business logic, but within the domain of business logic there are some questions that make sense rendered in terms of authorization, and other questions that make more sense rendered in terms of validation. If you treat auth as merely one of a dozen different properties that must be true about an entity when it is being created then it blurs that line in a way that I think is unhelpful.
Agreed.
Iām trying to come up with rules about applying authorization. I donāt think having all authorization in the specific functions (create_x, list_x, update_x, etcā¦) makes sense in many cases. I also donāt think having an Authorization module makes sense since it cares about every other (many?) contexts.
Now Iām leaning towards having auth in context, but implemented at the highest level of the entry point (Controller, Absinthe Resolver) so the auth lives close to the code it cares about, but is sufficiently high enough in the call stack to prevent multiple auth calls. Example:
# No idea why I wrote it with a with, but used a resolver cause...
# I appreciate your work š
defmodule MyAppWeb.Resolvers.Blog do
def update_post(author, args, %{context: %{current_user: _}}) do
with :ok <- Blogs.authorize(:update_post, author, args["post_id"]),
post = Blog.get_post(args["post_id"]),
{:ok, post} <- Blogs.update_post(post, args) do
{:ok, post}
else
error -> {:error, error}
end
end
In this scenario every context would have authorize functions that are called, most likely, up the call stack, but may well be implemented in the context if the scenario makes sense. Thatās all I got right now.