Is it possible to use pundit authorization with graphql

Viewed 1812

I want to do something like this:

authorize record, :some_action

In resolving a graphql field or mutation(example is mutation)

module Mutations::CreateLink
  CreateLink = GraphQL::Relay::Mutation.define do
    name "CreateLink"

    input_field :name, types.String
    input_field :url, types.String
    input_field :description, types.String

    return_field :link, Types::LinkType

    resolve -> (object, inputs, ctx) {
      Rails::logger.ap ctx[:current_user]
      Rails::logger.ap inputs[:name]
      ctx[:current_user]
      @link = Link.new(name: inputs[:name], url: inputs[:url], description: inputs[:description])
      authorize @link, :create?
      response = {
          link: @link
      }
    }
  end
end

When the above is run this error is shown: NoMethodError - GraphQL::Relay::Mutation can't define 'authorize'

Normally you write

include Pundit

In your controller, but adding it to the GraphqlController does not make any difference.

How do i make it so that graphql is aware of pundit and its methods?

4 Answers

Using a later version of graphql-ruby (I'm using 1.9.17 at the time of this writing), you can define an authorized? method in the mutation and include the following...

Pundit.authorize context[:current_user], @link, :create?

See https://github.com/varvet/pundit/blob/df96d2ae6bcf28991c1501d5ff0bde4c42aa4acd/lib/pundit.rb#L60-L76 for details on the Pundit authorize class method.

See https://graphql-ruby.org/mutations/mutation_authorization.html#can-this-user-perform-this-action for details on the authorized? method for graphql-ruby

The paid version of graphql-ruby has pundit integration.

But you can also use Pundit manually by calling:

Pundit.authorize(context[:current_user], record, :some_action)

Pundit.policy_scope(context[:current_user], RecordClass)

However, this won't satisfy verify_authorized and verify_policy_scoped. For that you need to call authorize and policy_scope on the controller, similar to @TamRock's answer:

graphql_controller.rb

class GraphqlController < ApplicationController
  include Pundit::Authorization
  after_action :verify_authorized
  after_action :verify_policy_scoped

  public :policy_scope
  public :authorize

  # ...

  def execute
    # ...

    context = {
      controller: self
    }

    # ...
  end
end

Then in the resolver:

context[:controller].policy_scope(RecordClass)
context[:controller].authorize(record, :some_action)
Related