{"id":13463341,"url":"https://github.com/nathanl/authority","last_synced_at":"2025-03-25T06:31:50.809Z","repository":{"id":2681139,"uuid":"3673495","full_name":"nathanl/authority","owner":"nathanl","description":"*CURRENTLY UNMAINTAINED*. Authority helps you authorize actions in your Rails app. It's ORM-neutral and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.","archived":true,"fork":false,"pushed_at":"2019-11-18T16:24:23.000Z","size":790,"stargazers_count":1204,"open_issues_count":0,"forks_count":68,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-03-23T06:43:15.312Z","etag":null,"topics":["authorization","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nathanl.png","metadata":{"files":{"readme":"README.markdown","changelog":"CHANGELOG.markdown","contributing":"CONTRIBUTING.markdown","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-03-09T18:31:06.000Z","updated_at":"2025-03-15T00:11:31.000Z","dependencies_parsed_at":"2022-08-29T08:02:09.016Z","dependency_job_id":null,"html_url":"https://github.com/nathanl/authority","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanl%2Fauthority","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanl%2Fauthority/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanl%2Fauthority/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nathanl%2Fauthority/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nathanl","download_url":"https://codeload.github.com/nathanl/authority/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245414186,"owners_count":20611357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorization","ruby"],"created_at":"2024-07-31T13:00:51.458Z","updated_at":"2025-03-25T06:31:50.456Z","avatar_url":"https://github.com/nathanl.png","language":"Ruby","funding_links":[],"categories":["Security","Ruby","Authentication and OAuth","Authorization"],"sub_categories":["Rails Authorization"],"readme":"# Authority *(CURRENTLY UNMAINTAINED)*\n\nAuthority is now unmaintained.\nUsers who have installed it decided to trust me, and I'm not comfortable transferring that trust to someone else on their behalf.\nHowever, if you'd like to fork it, feel free.\n\nGary Foster has provided a [script to migrate to Pundit](https://gist.github.com/garyfoster/5f1aba65b20ac7464e7e9642ea966c3f).\n\n## Overview\n\nAuthority helps you authorize actions in your Ruby app. It's **ORM-neutral** and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.\n\nAuthority will work fine with a standalone app or a single sign-on system. You can check roles in a database or permissions in a YAML file. It doesn't care! What it **does** do is give you an easy way to organize your logic and handle unauthorized actions.\n\nIf you're using it with Rails controllers, it requires that you already have some kind of user object in your application, accessible via a method like `current_user` (configurable).\n\n[![Gem Version](https://badge.fury.io/rb/authority.png)](https://rubygems.org/gems/authority)\n[![Build Status](https://secure.travis-ci.org/nathanl/authority.png?branch=master)](http://travis-ci.org/nathanl/authority)\n[![Code Climate](https://codeclimate.com/github/nathanl/authority.png)](https://codeclimate.com/github/nathanl/authority)\n[![Dependency Status](https://gemnasium.com/nathanl/authority.png)](https://gemnasium.com/nathanl/authority)\n[![Join the chat at https://gitter.im/nathanl/authority](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nathanl/authority?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n## Contents\n\n\u003cul\u003e\n  \u003cli\u003e\u003ca href=\"#overview\"\u003eOverview\u003c/a\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#flow_of_authority\"\u003eThe flow of Authority\u003c/a\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#defining_your_abilities\"\u003eDefining Your Abilities\u003c/a\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#wiring_it_together\"\u003eWiring It Together\u003c/a\u003e\n  \u003cul\u003e\n    \u003cli\u003e\u003ca href=\"#users\"\u003eUsers\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#models\"\u003eModels\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#authorizers\"\u003eAuthorizers\u003c/a\u003e\n    \u003cul\u003e\n      \u003cli\u003e\u003ca href=\"#passing_options\"\u003ePassing Options\u003c/a\u003e\u003c/li\u003e\n      \u003cli\u003e\u003ca href=\"#default_methods\"\u003eDefault methods\u003c/a\u003e\u003c/li\u003e\n      \u003cli\u003e\u003ca href=\"#testing_authorizers\"\u003eTesting Authorizers\u003c/a\u003e\u003c/li\u003e\n    \u003c/ul\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#controllers\"\u003eControllers\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#views\"\u003eViews\u003c/a\u003e\u003c/li\u003e\n  \u003c/ul\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#the_generic_can\"\u003eThe Generic `can?`\u003c/a\u003e\n  \u003cli\u003e\u003ca href=\"#security_violations_and_logging\"\u003eSecurity Violations \u0026amp; Logging\u003c/a\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#credits\"\u003eCredits\u003c/a\u003e\u003c/li\u003e\n  \u003cli\u003e\u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ca name=\"overview\"\u003e\n## Overview\n\nUsing Authority, you have:\n\n- Broad, **class-level** rules. Examples:\n  - \"Basic users cannot delete any Widget.\"\n  - \"Only admin users can create Offices.\"\n- Fine-grained, **instance-level** rules. Examples:\n  - \"Management users can only edit schedules with date ranges in the future.\"\n  - \"Users can't create playlists more than 20 songs long unless they've paid.\"\n- A clear syntax for permissions-based views. Examples:\n  - `link_to 'Edit Widget', edit_widget_path(@widget) if current_user.can_update?(@widget)`\n  - `link_to 'Keelhaul Scallywag', keelhaul_scallywag_path(@scallywag) if current_user.can_keelhaul?(@scallywag)`\n- Graceful handling of access violations: by default, it displays a \"you can't do that\" screen and logs the violation.\n- Minimal effort and mess.\n\nMost importantly, you have **total flexibility**: Authority does not constrain you into using a particular scheme of roles and/or permissions.\n\nAuthority lets you control access based on:\n\n- Roles in your app's database ([rolify](http://github.com/EppO/rolify) makes this easy)\n- Roles in a separate, single-sign-on app\n- Users' points (like StackOverflow)\n- Time and date\n- Weather, stock prices, vowels in the user's name, or **anything else you can check with Ruby**\n\nAll you have to do is define the methods you need on your authorizers. You have all the flexibility of normal Ruby classes.\n\n**You** make the rules; Authority enforces them.\n\n\u003ca name=\"flow_of_authority\"\u003e\n## The flow of Authority\n\nAuthority encapsulates all authorization logic in `Authorizer` classes. Want to do something with a model? **Ask its authorizer**.\n\nYou can specify a model's authorizer one of two ways:\n\n- specify the class itself: `authorizer = SomeAuthorizer`\n- specify the class's name: `authorizer_name = 'SomeAuthorizer'` (useful if the constant isn't yet loaded)\n\nIf you don't specify an authorizer, the model will:\n\n- Look for an authorizer with its name. Eg, `Comment` will look for `CommentAuthorizer`.\n- If that's not found, it will use `ApplicationAuthorizer`.\n\n**Models that have the same authorization rules should use the same authorizer**. In other words, if you would write the exact same methods on two models to determine who can create them, who can edit them, etc, then they should use the same authorizer.\n\nSome example groupings:\n\n         Simplest case                Logical groups                                 Most granular\n\n      ApplicationAuthorizer        ApplicationAuthorizer                         ApplicationAuthorizer\n               +                             +                                             +\n               |                    +--------+-------+                 +-------------------+-------------------+\n               |                    +                +                 +                   +                   +\n               |             BasicAuthorizer   AdminAuthorizer  CommentAuthorizer  ArticleAuthorizer  EditionAuthorizer\n               |                    +                +                 +                   +                   +\n       +-------+-------+            +-+       +------+                 |                   |                   |\n       +       +       +              +       +      +                 +                   +                   +\n    Comment Article Edition        Comment Article Edition          Comment             Article             Edition\n\nThe authorization process generally flows like this:\n\n                   current_user.can_create?(Article)                 # You ask this question, and the user\n                               +                                     # automatically asks the model...\n                               |\n                               v\n                 Article.creatable_by?(current_user)                 # The model automatically asks\n                               +                                     # its authorizer...\n                               |\n                               v\n               AdminAuthorizer.creatable_by?(current_user)           # *You define this method.*\n                               +                                     # If you don't, the inherited one\n                               |                                     # calls `default`...\n                               v\n        AdminAuthorizer.default(:creatable, current_user)            # *You define this method.*\n                                                                     # If you don't, it will use the one\n                                                                     # inherited from ApplicationAuthorizer.\n                                                                     # (Its parent, Authority::Authorizer,\n                                                                     # defines the method as `return false`.)\n\nIf the answer is `false` and the original caller was a controller, this is treated as a `SecurityViolation`. If it was a view, maybe you just don't show a link.\n\nThe authorization process for instances is different in that it calls the instance's `default` method before calling the class `default` method. This allows you to define default behaviour that requires access to the model instance to be determined (eg, assume any action on a blog post is allowed if that post is marked 'wiki').\n\n(Diagrams made with [AsciiFlow](http://asciiflow.com))\n\n\u003ca name=\"installation\"\u003e\n## Installation\n\nStarting from a clean commit status, add `authority` to your Gemfile, then `bundle`.\n\nIf you're using Rails, run `rails g authority:install`. Otherwise, pass a block to `Authority.configure` with [configuration options](https://github.com/nathanl/authority/blob/master/lib/generators/templates/authority_initializer.rb) somewhere when your application boots up.\n\n\u003ca name=\"defining_your_abilities\"\u003e\n## Defining Your Abilities\n\nEdit `config/initializers/authority.rb`. That file documents all your options, but one of particular interest is `config.abilities`, which defines the verbs and corresponding adjectives in your app. The defaults are:\n\n```ruby\nconfig.abilities =  {\n  :create =\u003e 'creatable',\n  :read   =\u003e 'readable',\n  :update =\u003e 'updatable',\n  :delete =\u003e 'deletable'\n}\n```\n\nThis option determines what methods are added to your users, models and authorizers. If you need to ask `user.can_deactivate?(Satellite)` and `@satellite.deactivatable_by?(user)`, add `:deactivate =\u003e 'deactivatable'` to the hash.\n\n\u003ca name=\"wiring_it_together\"\u003e\n## Wiring It Together\n\n\u003ca name=\"users\"\u003e\n### Users\n\n```ruby\n# Whatever class represents a logged-in user in your app\nclass User\n  # Adds `can_create?(resource)`, etc\n  include Authority::UserAbilities\n...\nend\n```\n\n\u003ca name=\"models\"\u003e\n### Models\n\n```ruby\nclass Article\n  # Adds `creatable_by?(user)`, etc\n  include Authority::Abilities\n\n  # Without this, 'ArticleAuthorizer' is assumed;\n  # if that doesn't exist, 'ApplicationAuthorizer'\n  self.authorizer_name = 'AdminAuthorizer'\n  ...\nend\n```\n\n\u003ca name=\"authorizers\"\u003e\n### Authorizers\n\nAdd your authorizers under `app/authorizers`, subclassing the generated `ApplicationAuthorizer`.\n\nThese are where your actual authorization logic goes. Here's how it works:\n\n- Instance methods answer questions about model instances, like \"can this user update this **particular** widget?\" (Within an instance method, you can get the model instance with `resource`).\n  - Any instance method you don't define (for example, if you didn't make a `def deletable_by?(user)`) will fall back to the corresponding class method. In other words, if you haven't said whether a user can update **this particular** widget, we'll decide by checking whether they can update **any** widget.\n- Class methods answer questions about model classes, like \"is it **ever** permissible for this user to update a Widget?\"\n  - Any class method you don't define (for example, if you didn't make a `def self.updatable_by?(user)`) will call that authorizer's `default` method.\n\nFor example:\n\n```ruby\n# app/authorizers/schedule_authorizer.rb\nclass ScheduleAuthorizer \u003c ApplicationAuthorizer\n  # Class method: can this user at least sometimes create a Schedule?\n  def self.creatable_by?(user)\n    user.manager?\n  end\n\n  # Instance method: can this user delete this particular schedule?\n  def deletable_by?(user)\n    resource.in_future? \u0026\u0026 user.manager? \u0026\u0026 resource.department == user.department\n  end\nend\n\n# undefined; calls `ScheduleAuthorizer.default(:updatable, user)`\nScheduleAuthorizer.updatable_by?(user)\n```\n\nAs you can see, you can specify different logic for every method on every model, if necessary. On the other extreme, you could simply supply a [default method](#default_methods) that covers all your use cases.\n\n\u003ca name=\"passing_options\"\u003e\n#### Passing Options\n\nAny options you pass when checking permissions will be passed right up the chain. One use case for this would be if you needed an associated instance in order to do a class-level check. For example:\n\n```ruby\n# I don't have a comment instance to check, but I need to know\n# which post the user wants to comment on\nuser.can_create?(Comment, :for =\u003e @post)\n```\n\nThis would ultimately call `creatable_by?` on the designated authorizer with two arguments: the user and `{:for =\u003e @post}`. If you've defined that method yourself, you'd need to ensure that it accepts the options hash before doing this, or you'd get a \"wrong number of arguments\" error.\n\nThere's nothing special about the hash key `:for`; I just think it reads well in this case. You can pass any options that make sense in your case.\n\nIf you **don't** pass options, none will be passed to your authorizer, either.\n\nAnd you could always handle the case above without options if you don't mind creating an extra model instance:\n\n```ruby\nuser.can_create?(Comment.new(:post =\u003e @post))\n```\n\n\u003ca name=\"default_methods\"\u003e\n#### Default Methods\n\nAny class method you don't define on an authorizer will call the `default` method on that authorizer. This method is defined on `Authority::Authorizer` to simply return false. This is a 'whitelisting' approach; any permission you haven't specified (which falls back to the default method) is considered forbidden.\n\nYou can override this method in your `ApplicationAuthorizer` and/or per authorizer. For example, you might want one that looks up the user's roles and correlates them with permissions:\n\n```ruby\n# app/authorizers/application_authorizer.rb\nclass ApplicationAuthorizer \u003c Authority::Authorizer\n\n  # Example call: `default(:creatable, current_user)`\n  def self.default(able, user)\n    has_role_granting?(user, able) || user.admin?\n  end\n\n  protected\n\n  def has_role_granting?(user, able)\n    # Does the user have any of the roles which give this permission?\n    (roles_which_grant(able) \u0026 user.roles).any?\n  end\n\n  def roles_which_grant(able)\n    # Look up roles for the current authorizer and `able`\n    ...\n  end\nend\n```\n\nIf your system is uniform enough, **this method alone might handle all the logic you need**.\n\n\u003ca name=\"testing_authorizers\"\u003e\n#### Testing Authorizers\n\nOne nice thing about putting your authorization logic in authorizers is the ease of testing. Here's a brief example.\n\n```ruby\n# An authorizer shared by several admin-only models\ndescribe AdminAuthorizer do\n\n  before :each do\n    @user  = FactoryGirl.build(:user)\n    @admin = FactoryGirl.build(:admin)\n  end\n\n  describe \"class\" do\n    it \"lets admins update\" do\n      expect(AdminAuthorizer).to be_updatable_by(@admin)\n    end\n\n    it \"doesn't let users update\" do\n      expect(AdminAuthorizer).not_to be_updatable_by(@user)\n    end\n  end\n\n  describe \"instances\" do\n\n    before :each do\n      # A mock model that uses AdminAuthorizer\n      @admin_resource_instance = mock_admin_resource\n    end\n\n    it \"lets admins delete\" do\n      expect(@admin_resource_instance.authorizer).to be_deletable_by(@admin)\n    end\n\n    it \"doesn't let users delete\" do\n      expect(@admin_resource_instance.authorizer).not_to be_deletable_by(@user)\n    end\n\n  end\n\nend\n```\n\n\u003ca name=\"controllers\"\u003e\n### Controllers\n\nIf you're using Rails, ActionController support will be loaded in through a Railtie. Otherwise, you'll want to integrate it into your framework yourself. [Authority's controller](https://github.com/nathanl/authority/blob/master/lib/authority/controller.rb) is an excellent starting point.\n\nYou can check authorization in your controllers in one of two ways:\n\n- `authorize_actions_for Llama` protects multiple controller actions with a `before_filter`, which performs a **class-level** check. If the current user is never allowed to delete a `Llama`, they'll never even get to the controller's `destroy` method.\n- `authorize_action_for @llama` can be called inside a single controller action, and performs an **instance-level** check. If called inside `update`, it will check whether the current user is allowed to update this particular `@llama` instance.\n\nIf either method finds a user attempting something they're not authorized to do, a [Security Violation](#security_violations_and_logging) will result.\n\nHow does `authorize_actions_for` know to check `deletable_by?` before the controller's `destroy` action? It checks your configuration. These mappings are configurable globally from the initializer file. Defaults are as follows:\n\n```ruby\nconfig.controller_action_map = {\n :index   =\u003e 'read',    # `index` controller action will check `readable_by?`\n :show    =\u003e 'read',\n :new     =\u003e 'create',  # `new` controller action will check `creatable_by?`\n :create  =\u003e 'create',  # ...etc\n :edit    =\u003e 'update',\n :update  =\u003e 'update',\n :destroy =\u003e 'delete'\n}\n```\n\nThey are also configurable per controller, as follows:\n\n```ruby\nclass LlamasController \u003c ApplicationController\n\n  # Check class-level authorizations before all actions except :create\n  # Also, to authorize this controller's 'neuter' action, ask whether `current_user.can_update?(Llama)`\n  authorize_actions_for Llama, :except =\u003e :create, :actions =\u003e {:neuter =\u003e :update},\n\n  # To authorize this controller's 'breed' action, ask whether `current_user.can_create?(Llama)`\n  # To authorize its 'vaporize' action, ask whether `current_user.can_delete?(Llama)`\n  authority_actions :breed =\u003e 'create', :vaporize =\u003e 'delete'\n\n  ...\n\n  def edit\n    @llama = Llama.find(params[:id])\n    authorize_action_for(@llama)        # Check to see if you're allowed to edit this llama. failure == SecurityViolation\n  end\n\n  def update\n    @llama = Llama.find(params[:id])\n    authorize_action_for(@llama)        # Check to see if you're allowed to edit this llama.\n    @llama.attributes = params[:llama]  # Don't save the attributes before authorizing\n    authorize_action_for(@llama)        # Check again, to see if the changes are allowed.\n    if @llama.save?\n    # etc\n  end\n\nend\n```\n\nYou can pass extra arguments to your authorization checks in these controller helpers:\n\n- `authorize_actions_for(Llama, args: [{:mamma =\u003e true}]`\n- `authorize_action_for(@llama, :sporting =\u003e @hat_style)`\n\nGenerally, though, your authorization will depend on some attribute or association of the model instance, so the authorizer can check `@llama.neck_strength` and `@llama.owner.nationality`, etc, without needing any additional information.\n\nNote that you can also call `authority_actions` as many times as you like, so you can specify one mapping at a time if you prefer:\n\n```ruby\nclass LlamasController \u003c ApplicationController\n  def breed\n    # some code\n  end\n  authority_actions :breed =\u003e 'create'\n\n  def vaporize\n    # some code\n  end\n  authority_actions :vaporize =\u003e 'delete'\nend\n```\n\nIf you have a controller that dynamically determines the class it's working with, you can pass the name of a controller instance method to `authorize_actions_for` instead of a class, and the class will be looked up when a request is made.\n\n```ruby\nclass LlamasController \u003c ApplicationController\n\n  authorize_actions_for :llama_class\n\n  def llama_class\n    # This method can simply return a class...\n    [StandardLlama, LludicrousLlama].sample\n\n    # ... or an array with a class and some options\n    [OptionLladenLlama, {country: 'Peru'}]\n  end\nend\n```\n\nIf you want to authorize all actions the same way, use the special `all_actions` hash key. For instance, if you have nested resources, you might say \"you're allowed to do anything you like with an employee if you're allowed to update their employer\".\n\n```ruby\nclass EmployeesController \u003c ApplicationController\n  authorize_actions_for :parent_resource, all_actions: :update\n  private\n  def parent_resource\n    Employer.find(params[:employer_id])\n  end\nend\n```\n\nFinally, you can enforce that every controller action runs an authorization check using the class method `ensure_authorization_performed`, which sets up an `after_filter` to raise an exception if it wasn't. Any `only` or `except` arguments will be passed to `after_filter`. You can also use `if` or `unless` to specify the name of a controller method which determines whether it's necessary.\n\nSince this runs in an `after_filter`, it obviously doesn't prevent the action, it just alerts you that no authorization was performed. Therefore, it's most useful in development. An example usage might be:\n\n```ruby\nclass ApplicationController \u003c ActionController::Base\n  ensure_authorization_performed :except =\u003e [:index, :search], :if =\u003e :auditing_security?, :unless =\u003e :devise_controller?\n\n  def auditing_security?\n    Rails.env != 'production'\n  end\nend\n```\n\nIf you want a skippable filter, you can roll your own using the instance method, also called `ensure_authorization_performed`.\n\n\u003ca name=\"views\"\u003e\n### Views\n\nAssuming your user object is available in your views, you can do all kinds of conditional rendering. For example:\n\n```ruby\nlink_to 'Edit Widget', edit_widget_path(@widget) if current_user.can_update?(@widget)\n```\n\nIf the user isn't allowed to edit widgets, they won't see the link. If they're nosy and try to hit the URL directly, they'll get a [Security Violation](#security_violations_and_logging) from the controller.\n\n\u003ca name=\"the_generic_can\"\u003e\n## The Generic `can?`\n\nAuthority is organized around protecting resources. But **occasionally** you **may** need to authorize something that has no particular resource. For that, it provides the generic `can?` method. It works like this:\n\n```ruby\ncurrent_user.can?(:view_stats_dashboard) # calls `ApplicationAuthorizer.authorizes_to_view_stats_dashboard?`\ncurrent_user.can?(:view_stats_dashboard, :on =\u003e :tuesdays, :with =\u003e :tea) # same, passing the options\n\n# application_authorizer.rb\nclass ApplicationAuthorizer \u003c Authority::Authorizer\n  # ...\n  def self.authorizes_to_view_stats_dashboard?(user, options = {})\n    user.has_role?(:manager) # or whatever\n  end\nend\n```\n\nUse this very sparingly, and consider it a [code smell](http://en.wikipedia.org/wiki/Code_smell). Overuse will turn your `ApplicationAuthorizer` into a junk drawer of methods. Ask yourself, \"am I sure I don't have a resource for this? Should I have one?\"\n\n\u003ca name=\"security_violations_and_logging\"\u003e\n## Security Violations \u0026 Logging\n\nIf you're using Authority's `ActiveController` integration or have used it as a template for your own, your application will handle unauthorized requests with `403 Forbidden` automatically.\n\nIf you use Authority to [conditionally render links](#security_violations_and_logging), users will only see links for actions they're authorized to take. If a user deliberately tries to access a restricted resource (for instance, by typing the URL directly), Authority raises and rescues an `Authority::SecurityViolation`.\n\nWhen it rescues the exception, Authority calls whatever controller method is specified by your `security_violation_handler` option, handing it the exception. The default handler is `authority_forbidden`, which Authority mixes in to your `ApplicationController`. It does the following:\n\n- Renders `public/403.html`\n- Logs the violation to whatever logger you configured.\n\nYou can define your own `authority_forbidden` method on `ApplicationController` and/or any other controller. For example:\n\n```ruby\n# Send 'em back where they came from with a slap on the wrist\ndef authority_forbidden(error)\n  Authority.logger.warn(error.message)\n  redirect_to request.referrer.presence || root_path, :alert =\u003e 'You are not authorized to complete that action.'\nend\n```\n\nYour method will be handed the `SecurityViolation`, which has a `message` method. In case you want to build your own message, it also exposes `user`, `action` and `resource`.\n\nWhen a user action is successfully authorized, Authority will call `authority_success` on your controller.\nBy default, this does nothing, but you can override it to log the event or do something else.\nFor instance:\n\n```ruby\ndef authority_success(user, action, resource)\n  Authority.logger.info \"user #{user} was authorized to #{action} resource #{resource}\"\nend\n```\n\n\u003ca name=\"credits\"\u003e\n## Credits, AKA 'Shout-Outs'\n\n- [adamhunter](https://github.com/adamhunter) for pairing with me on this gem. The only thing faster than his typing is his brain.\n- [kevmoo](https://github.com/kevmoo), [MP211](https://github.com/MP211), and [scottmartin](https://github.com/scottmartin) for pitching in.\n- [nkallen](https://github.com/nkallen) for writing [a lovely blog post on access control](http://blog.pivotal.io/labs/labs/access-control-permissions-in-rails-access-control-permissions-in-rails) when he worked at Pivotal Labs. I cried sweet tears of joy when I read that in 2010. I was like, \"Zee access code, she is so BEEUTY-FUL!\"\n- [jnunemaker](https://github.com/jnunemaker) for later creating [Canable](http://github.com/jnunemaker/canable), another inspiration for Authority.\n- [TMA](http://www.tma1.com) for sponsoring the initial releases of Authority.\n\n\u003ca name=\"contributing\"\u003e\n\n## Responses, AKA 'Hollaback'\n\nDo you like Authority? Has it cleaned up your code, made you more personable, and taught you the Secret to True Happiness? Awesome! I'd **love** to get email from you - see my Github profile for the address.\n\n## Contributing\n\nHow can you contribute? Let me count the ways.\n\n### 1. Publicity\n\nIf you like Authority, tell people! Blog, tweet, comment, or even... [shudder]... talk with people *in person*. If you feel up to it, I mean. It's OK if you don't.\n\n### 2. Documentation\n\nAdd examples to the [wiki](http://github.com/nathanl/authority/wiki) to help others solve problems like yours.\n\n### 3. Issues\n\nTell me your problems and/or ideas.\n\n### 4. Code or documentation\n\n1. Have an idea. If you don't have one, check the TODO file or grep the project for 'TODO' comments.\n2. Open an issue so we can talk it over.\n3. Fork this project\n4. Create your feature branch (`git checkout -b my-new-feature`)\n5. `bundle install` to get all dependencies\n6. `rspec spec` to run all tests.\n7. Update/add tests for your changes and code until they pass.\n8. Commit your changes (`git commit -am 'Added some feature'`)\n9. Push to the branch (`git push origin my-new-feature`)\n10. Create a new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathanl%2Fauthority","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnathanl%2Fauthority","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnathanl%2Fauthority/lists"}