Bypassing tenancy & authorization to load related data in special read

Th following action reads the received invitation of a user to join the establishment of an organization (both are tenants, org being the top tenant).
read :get_received_invitation do
multitenancy :bypass
get_by :id
prepare build(load: [:inviter, establishment: [:organization]])
filter expr(email == ^actor(:email))
end
read :get_received_invitation do
multitenancy :bypass
get_by :id
prepare build(load: [:inviter, establishment: [:organization]])
filter expr(email == ^actor(:email))
end
It successfully reads the invitation (which belongs to the establishment tenant) thanks to multitenancy :bypass However, loading inviter (an establishment_user) requires a tenant to be set, and establishment returns nil — I’m guessing because the policy doesn’t allow reading establishment data unless you’re a member, which we aren’t here (yet). This means we never even reach organization (top-level tenant). How can I bypass tenancy & authorization policies just for this exceptional case so I can load related data (inviter, establishment, organization)?
Solution:
:bypass_all IIRC
Jump to solution
3 Replies
Solution
ZachDaniel
ZachDaniel2mo ago
:bypass_all IIRC
ZachDaniel
ZachDaniel2mo ago
will bypass tenancy for loaded data as well
Joan Gavelán
Joan GavelánOP2mo ago
Awesome, that fixes the tenancy problem Is there a way to bypass the authorization directly from the prepare here?
read :get_received_invitation do
get_by :id
multitenancy :bypass_all
prepare build(load: [inviter: [:user], establishment: [:organization]])
filter expr(email == ^actor(:email))
end
read :get_received_invitation do
get_by :id
multitenancy :bypass_all
prepare build(load: [inviter: [:user], establishment: [:organization]])
filter expr(email == ^actor(:email))
end
There is a lot I'm loading here and writing policies for each one of them only for this special use case doesn't feel like the right approach By the way I tried this
read :get_received_invitation do
get_by :id
multitenancy :bypass_all

prepare fn query, _context ->
query
|> Ash.Query.load([inviter: [:user], establishment: [:organization]],
authorize?: false
)
end

filter expr(email == ^actor(:email))
end
read :get_received_invitation do
get_by :id
multitenancy :bypass_all

prepare fn query, _context ->
query
|> Ash.Query.load([inviter: [:user], establishment: [:organization]],
authorize?: false
)
end

filter expr(email == ^actor(:email))
end
But still getting nil for the loaded relationships Ok nevermind, implementing the policies was pretty straightforward after establishing the correct relationships. Here is an example:
# establishment_user.ex (inviter)
authorize_if expr(exists(invitations, email == ^actor(:email)))
# establishment_user.ex (inviter)
authorize_if expr(exists(invitations, email == ^actor(:email)))
Thanks for your support Zach!

Did you find this page helpful?