Skip to content

Instantly share code, notes, and snippets.

@rmosolgo
Created December 1, 2021 15:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmosolgo/44703c57612e61bd20b261a5d4b607b1 to your computer and use it in GitHub Desktop.
Save rmosolgo/44703c57612e61bd20b261a5d4b607b1 to your computer and use it in GitHub Desktop.
Argument auth with loads
require "bundler/inline"
gemfile do
gem "graphql", "1.13.0"
gem "graphql-pro", "1.20.3"
gem "pundit"
end
require "ostruct"
class Schema < GraphQL::Schema
# first, base classes with Pundit as needed:
class BaseArgument < GraphQL::Schema::Argument
include GraphQL::Pro::PunditIntegration::ArgumentIntegration
end
class BaseField < GraphQL::Schema::Field
include GraphQL::Pro::PunditIntegration::FieldIntegration
pundit_role nil
argument_class BaseArgument
end
class BaseObject < GraphQL::Schema::Object
include GraphQL::Pro::PunditIntegration::ObjectIntegration
field_class BaseField
end
# some pundit policies
class QueryPolicy
def initialize(viewer, object)
@viewer = viewer
@object = object
end
def load_thing?
@viewer.load_thing
end
end
class ThingPolicy
def initialize(viewer, object)
@viewer = viewer
@object = object
end
def view?
@viewer.view_thing
end
end
# Then the schema:
class Thing < BaseObject
pundit_policy_class ThingPolicy
pundit_role :view
field :name, String
end
class Query < BaseObject
pundit_policy_class QueryPolicy
pundit_role nil # No auth for base query
field :thing, Thing, null: true do
argument :thing_id, ID, loads: Thing, pundit_role: :load_thing
end
def thing(thing:)
thing
end
end
query(Query)
def self.object_from_id(id, ctx)
puts "Loading from #{id.inspect}"
{ name: id, graphql_type: Thing }
end
def self.resolve_type(_abs_type, obj, ctx)
obj.fetch(:graphql_type)
end
def self.unauthorized_object(err)
raise GraphQL::ExecutionError, err.message
end
end
# This is fully authorized:
pp Schema.execute("{ thing(thingId: \"hat\") { name } }", context: { current_user: OpenStruct.new(view_thing: true, load_thing: true)}).to_h
# Loading from "hat"
# {"data"=>{"thing"=>{"name"=>"hat"}}}
# This one succeeds to load, but fails arg auth:
pp Schema.execute("{ thing(thingId: \"hat\") { name } }", context: { current_user: OpenStruct.new(view_thing: true)}).to_h
# Loading from "hat"
# {"data"=>{"thing"=>nil},
# "errors"=>
# [{"message"=>"Failed Schema::Query's authorization check on field thing",
# "locations"=>[{"line"=>1, "column"=>3}],
# "path"=>["thing"]}]}
# This one loads, but then the check on the loaded object fails auth:
pp Schema.execute("{ thing(thingId: \"hat\") { name } }", context: { current_user: OpenStruct.new(load_thing: true)}).to_h
# Loading from "hat"
# {"data"=>{"thing"=>nil},
# "errors"=>
# [{"message"=>"An instance of Hash failed Thing's authorization check",
# "locations"=>[{"line"=>1, "column"=>3}],
# "path"=>["thing"]}]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment