nexus_cqrs_auth

Authorisation for the Nexus CQRS pattern.

Installation

Add this line to your application's Gemfile:

gem 'nexus_cqrs_auth'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install nexus_cqrs_auth

Usage

When setting up the message bus, attach the authorisation middleware to it:

middleware_stack = Middleware::Builder.new do |b|
  b.use NexusCqrsAuth::AuthMiddleware
end

bus = Bus.new(middleware: middleware_stack)

You will also need to set metadata on each message (command/query) before dispatching it to the bus:

command.(:current_user, user)
execute(command)

How you set this data, and where you get the current user from is application specific.

For example, a helper included in all GraphQL types could look like this:

module GraphQlCqrsHelpers
  def execute(command)
    command_executor.execute(enrich_message(command))
  end

  def query(query)
    query_executor.execute(enrich_message(query))
  end

  def command_executor
    @command_executor ||= $COMMAND_EXECUTOR
  end

  def query_executor
    @query_executor ||= $QUERY_EXECUTOR
  end

  private

  def enrich_message(message)
    message.(:current_user, @context[:current_user])
    message
  end
end

You can then write various policies to setup authorisation in CQRS flows.

More information about policies can be found in the Pundit documentation.

Remember to create a base policy at: app/policies/application_policy.rb

Bus level policy

Create a policy class in app/policies/my_message_policy.rb

class MyMessagePolicy < ApplicationPolicy
  def initialize(user, message)
    @user = user
    @query = message
  end

  def authorise?
    true
  end
end

The authorise? method will be called before the message handler. If authorise? returns false, execution of the bus will halt and a Pundit::NotAuthorizedError will be raised.

Record level policy

You can write policies for records:

class PostPolicy < ApplicationPolicy
  def initialize(user, post)
    @user = user
    @post = post
  end

  def publish_post?
    true
  end
end

You can then authorise a particular Posts by calling the policy from a command handler:

class PublishPostHandler < NexusCqrs::BaseCommandHandler
  include NexusCqrsAuth

  # @param [Commands::PublishPost] command
  def call(command)
    post = Post.find(command.post_id)
    authorize(command, post)
    post.is_published = true
    post.save
  end
end

The NexusCqrsAuth module must be included in the handler.

authorize should be called with the domain message (e.g. command) and the record. The policy for that record type (e.g. PostPolicy) will be called and the scope with the same name as the command (PublishPost -> publish_post?) will be called.

If the scope returns false, then a Pundit::NotAuthorizedError will be raised.

Development

To contribute to this gem, simple clone the repository, run bundle install and run tests:

```shell script bundle exec rspec bundle exec rubocop


## Releasing

The release process is tied to the git tags. Simply creating a new tag and pushing will trigger a new release to rubygems.