[How to] authorize specific arguments in a mutation
Tao-Galasse opened this issue ยท 1 comments
Hi there @palkan! ๐
First of all, thanks for your amazing gem :)
Here is my issue: I would like to be able to authorize some specific arguments in a mutation, and not only the mutation as a whole.
Let's say I have a mutation to update a User. Maybe the user itself could update its first_name, but only the admin could upgrade its role, and the manager could assign it in a specific team.
I would like to do something like this:
class Mutations::UpdateUser < BaseMutation
argument :user_id, ID, loads: Types::UserType, required: true
argument :first_name, String, required: false # no specific authorization here
argument :last_name, String, required: false # no specific authorization here
argument :team_id, ID, loads: Types::Team, required: false, authorize: true
argument :role, Types::RoleEnum, required: false, authorize: true
def resolve(user:, **params)
authorize! user, to: :update?
user.update!(params)
{ user: user }
end
end
And then, in my policy class, I could have something like this:
class UserPolicy < ApplicationPolicy
def team? = user.manager? || user.admin?
def role? = user.admin?
def update? # my mutation authorization logic
end
For now, the only way to achieve this I found was to do all this argument-validation logic inside my resolver, but the implementation feels a bit lame.
For example:
def resolve(user:, team: nil, role: nil, **params)
authorize! user, to: :update?
authorize! user, to: :update_team? if team
authorize! user, to: :update_role? if role
end
Is there a better way to manage this?
Thanks a lot :)
Hey! Thank you for our feedback!
We've been thinking on a workaround for this problem for a while, see: #24 (and other linked discussions). Still, no interface we agreed upon.
Using the current API, I see two options:
- Passing input as an optional context (
authorize :input, optional: true
in your policy andauthorize! ..., context: {input:}
) - Using scopes to filter input parameters (similarly to permitted attributes)
The latter approach is preferable if you want to support partial application, i.e., ignore unpermitted fields and continue execution with what's left.