• Stars
    star
    149
  • Rank 240,038 (Top 5 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 5 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Action Policy integration for GraphQL

Gem Version Build JRuby Build Documentation

Action Policy GraphQL

This gem provides an integration for using Action Policy as an authorization framework for GraphQL applications (built with graphql ruby gem).

This integration includes the following features:

📑 Documentation

Sponsored by Evil Martians

Installation

Add this line to your application's Gemfile:

gem "action_policy-graphql"

Usage

NOTE: this is a quick overview of the functionality provided by the gem. For more information see the documentation.

To start using Action Policy in GraphQL-related code, you need to enhance your base classes with ActionPolicy::GraphQL::Behaviour:

# For fields authorization, lists scoping and rules exposing
class Types::BaseObject < GraphQL::Schema::Object
  include ActionPolicy::GraphQL::Behaviour
end

# For using authorization helpers in mutations
class Types::BaseMutation < GraphQL::Schema::Mutation
  include ActionPolicy::GraphQL::Behaviour
end

# For using authorization helpers in resolvers
class Types::BaseResolver < GraphQL::Schema::Resolver
  include ActionPolicy::GraphQL::Behaviour
end

authorize: *

You can add authorization to the fields by specifying the authorize: * option:

field :home, Home, null: false, authorize: true do
  argument :id, ID, required: true
end

# field resolver method
def home(id:)
  Home.find(id)
end

The code above is equal to:

field :home, Home, null: false do
  argument :id, ID, required: true
end

def home(id:)
  Home.find(id).tap { |home| authorize! home, to: :show? }
end

You can customize the authorization options, e.g. authorize: {to: :preview?, with: CustomPolicy}.

If you don't want to raise an exception but return a null instead, you should set a raise: false option.

Note: it does not make too much sense to use authorize in mutations since it's checking authorization rules after mutation is executed. Therefore authorize marked as deprecated when used in mutations and will raise error in future releases.

authorized_scope: *

You can add authorized_scope: true option to the field (list or connection field) to apply the corresponding policy rules to the data:

class CityType < ::Common::Graphql::Type
  # It would automatically apply the relation scope from the EventPolicy to
  # the relation (city.events)
  field :events, EventType.connection_type, null: false, authorized_scope: true

  # you can specify the policy explicitly
  field :events, EventType.connection_type, null: false, authorized_scope: {with: CustomEventPolicy}
end

NOTE: you cannot use authorize: * and authorized_scope: * at the same time but you can combine preauthorize: * or authorize_field: * with authorized_scope: *.

preauthorize: *

If you want to perform authorization before resolving the field value, you can use preauthorize: * option:

field :homes, [Home], null: false, preauthorize: {with: HomePolicy}

def homes
  Home.all
end

The code above is equal to:

field :homes, [Home], null: false

def homes
  authorize! "homes", to: :index?, with: HomePolicy
  Home.all
end

NOTE: we pass the field's name as the record to the policy rule. We assume that preauthorization rules do not depend on the record itself and pass the field's name for debugging purposes only.

You can customize the authorization options, e.g. preauthorize: {to: :preview?, with: CustomPolicy}.

NOTE: unlike authorize: * you MUST specify the with: SomePolicy option. The default authorization rule depends on the type of the field:

  • for lists we use index? (configured by ActionPolicy::GraphQL.default_preauthorize_list_rule parameter)
  • for singleton fields we use show? (configured by ActionPolicy::GraphQL.default_preauthorize_node_rule parameter)

authorize_field: *

If you want to perform authorization before resolving the field value on the base of the upper object, you can use authorize_field: * option:

field :homes, Home, null: false, authorize_field: true

def homes
  Home.all
end

The code above is equal to:

field :homes, [Home], null: false

def homes
  authorize! object, to: :homes?
  Home.all
end

By default we use #{underscored_field_name}? authorization rule.

You can customize the authorization options, e.g. authorize_field: {to: :preview?, with: CustomPolicy}.

expose_authorization_rules

You can add permissions/authorization exposing fields to "tell" clients which actions could be performed against the object or not (and why).

For example:

class ProfileType < ::Common::Graphql::Type
  # Adds can_edit, can_destroy fields with
  # AuthorizationResult type.

  # NOTE: prefix "can_" is used by default, no need to specify it explicitly
  expose_authorization_rules :edit?, :destroy?, prefix: "can_"
end

Then the client could perform the following query:

{
  post(id: $id) {
    canEdit {
      # (bool) true|false; not null
      value
      # top-level decline message ("Not authorized" by default); null if value is true
      message
      # detailed information about the decline reasons; null if value is true
      reasons {
        details # JSON-encoded hash of the failure reasons (e.g., {"event" => [:seats_available?]})
        fullMessages # Array of human-readable reasons (e.g., ["This event is sold out"])
      }
    }

    canDestroy {
      # ...
    }
  }
}

You can specify a custom field name as well (only for a single rule):

class ProfileType < ::Common::Graphql::Type
  # Adds can_create_post field.

  expose_authorization_rules :create?, with: PostPolicy, field_name: "can_create_post"
end

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/palkan/action_policy-graphql.

License

The gem is available as open source under the terms of the MIT License.

More Repositories

1

logidze

Database changes log for Rails
Ruby
1,555
star
2

action_policy

Authorization framework for Ruby/Rails applications
Ruby
1,333
star
3

isolator

Detect non-atomic interactions within DB transactions
Ruby
814
star
4

anyway_config

Configuration library for Ruby gems and applications
Ruby
719
star
5

active_delivery

Ruby framework for keeping all types of notifications (mailers, push notifications, whatever) in one place
Ruby
585
star
6

n_plus_one_control

RSpec and Minitest matchers to prevent N+1 queries problem
Ruby
543
star
7

store_attribute

ActiveRecord extension which adds typecasting to store accessors
Ruby
344
star
8

view_component-contrib

A collection of extension and developer tools for ViewComponent
Ruby
318
star
9

litecable

Lightweight Action Cable implementation (Rails-free)
Ruby
285
star
10

acli

Action Cable command-line client
Ruby
222
star
11

action-cable-testing

Action Cable testing utils
Ruby
209
star
12

rubanok

Parameters-based transformation DSL
Ruby
200
star
13

active_event_store

Rails Event Store in a more Rails way
Ruby
167
star
14

engems

Rails component-based architecture on top of engines and gems (showroom)
Ruby
136
star
15

influxer

InfluxDB ActiveRecord-style
Ruby
118
star
16

abstract_notifier

ActionMailer-like interface for any type of notifications
Ruby
116
star
17

wsdirector

All the world's a server, and all the men and women merely clients
Ruby
99
star
18

pgrel

ActiveRecord extension for querying hstore and jsonb
Ruby
93
star
19

gem-check

GemCheck: Writing Better Ruby Gems Checklist
CSS
93
star
20

turbo-music-drive

Exploring Turbo future features while building a music library app
Ruby
89
star
21

rbytes

Ruby Bytes helps you build, deploy and install Ruby and Rails application templates
Ruby
65
star
22

faqueue

Researching background jobs fairness
Ruby
63
star
23

downstream

Straightforward way to implement communication between Rails Engines using the Publish-Subscribe pattern.
Ruby
47
star
24

influx_udp

Erlang InfluxDB UDP writer
Erlang
31
star
25

newgem

Custom script to generate new gems
Ruby
30
star
26

ruby-dip

Docker-based development environment for hacking Ruby MRI
Dockerfile
30
star
27

turbo-view-transitions

View Transitions API for Turbo
TypeScript
28
star
28

erlgrpc

GRPC client for Erlang
Erlang
25
star
29

as3_p2plocal

as3 lib for local p2p connections (serverless rtmfp)
ActionScript
25
star
30

rails-intest-views

Generate view templates dynamically in Rails tests
Ruby
20
star
31

sharelatex-vagrant-ansible

Vagrant + Ansible configuration for ShareLatex
Shell
12
star
32

docsify-namespaced

Docsify plugin to work with namespaces
JavaScript
11
star
33

docs-example

Playground for dealing with documentation engines
7
star
34

ruby-russia-2020

RubyRussia 2020 "Frontendless Rails" workshop demo app
Ruby
6
star
35

engine-cable-app

Experimenting with Action Cable and engines
Ruby
6
star
36

palkan

It's me
4
star
37

ruby-compatibility-examples

Collections of reproduction cases for TruffleRuby vs. MRI (in)compatibility
Ruby
3
star
38

erffmpeg

Erlang wrapper for some ffmpeg
C
3
star
39

th-dummy

TH Dummy
Ruby
2
star
40

ulitos

Erlang utils modules
Erlang
2
star
41

meetings

Good old Teachbase Meetings client
ActionScript
2
star
42

macos-setup

Shell
1
star
43

bitrix-orm

Bitrix kinda ORM for IBlockElements and CUser.
PHP
1
star
44

adventofcode2018

https://adventofcode.com
Rust
1
star
45

tb_utils

ActionScript 3 library
ActionScript
1
star
46

rebar_templates

Custom rebar templates
Erlang
1
star