Using args in policies
I'm trying to figure out how to use args in my policy as I've seen in the documentation but all I ever get back is nil. Any help would be appreciated. Here is my code. How does one get the attributes to use in your policies? I see in the docs something like
^arg(:attribute_name)
but doing so is not working for me. This is my resource.

14 Replies
Here is a picture of the relevant section
I have a feeling I'm not importing something I need to be.
arg
is only used for accessing input arguments (i.e argument :amount, :decimal
)
In your case, you can just do expr(bank_account_id == ^actor(:id))
for exampleOkay, that seems to work in the same manner as using
authorize_if relates_to_actor_via(:bank_account)
in that, when doing a query to read a transaction, if an actor is passed at all, even an incorrect one, it will return {:ok, []}
. So it does not return anything, but it does say :ok
. Is this the expected behaviour? I was expecting it to return :error
What its actually doing is restricting the query to only the results that would pass your policies
So its attaching a
bank_account_id == ^actor(:id)
filter to the query itself
If you want to produce a forbidden on read actions, it tends to get a bit more manual, because introspecting filters is not typically a good idea. So what you'd do is something like this:
By not using filter checks, and instead using simple checks, you can produce forbidden results. But using expr/1
will filter the data. Its a bit magical, I know, but its a really smart solver under the hood.Right. That is interesting. I think the "authorize" wording confused me. In essence the expr() is saying, this person is authorized to access data but only this particular data so only return that. When I think of "authorize" I think "can they do this at all". I suppose the authorize_if works similar to graphql, which also posts the data then has to check if it can return.
forbid_if seems to work differently?
Well, its sort of a natural extension to "can the user see this at all", i.e "well just show me the ones they can see". So the tooling provides a way to express essentially both at the same time.
There are security implications to that also which is part of the reason we do it
i.e if you say
?account_id=<some_account_id>
and the system says Forbidden!
but then you use a different account_id and it says Not Found!
, you can start to enumerate/discover the data under the hood.
So using filter checks can prevent that sort of thing from being a problem by doing both jobs at once.
All of the checks work effectively the same, it just causes us to remix the expressions differently
So would you say returning an
:ok
with no data is more secure than returning forbidden?generally speaking, yes.
interesting...
Not an absolute thing though, and you are more than welcome to write explicit checks to say "can you do this action at all"
its just not what
expr/1
is for is allSo why does, this not work.
forbid_unless expr(bank_account_id != ^actor(:id))
A policy must be explicitly allowed
so if you only have a
forbid_unless
there is no way to actually authorize the policy
i.e if you go from top to bottom and follow each step, nothing says "authorized"
is a way to do a "white-list" style policy
You can mix and match simple checks and filter checks, also:
That would require that a user uses their own account id always, but filter public == true
if the user is not an adminRight, okay, this is all starting to make sense now.
Thank you for taking so much time and really explaining this. You answered my first questions ages ago, but now I am really getting a whole picture.
Glad to help!