{"id":15715365,"url":"https://github.com/cloudflare/authr","last_synced_at":"2025-04-10T01:14:52.094Z","repository":{"id":30450368,"uuid":"107581181","full_name":"cloudflare/authr","owner":"cloudflare","description":":key: a flexible and expressive approach to access-control","archived":false,"fork":false,"pushed_at":"2024-09-25T22:33:15.000Z","size":605,"stargazers_count":49,"open_issues_count":7,"forks_count":13,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-10T01:14:44.425Z","etag":null,"topics":["access-control","authorization","golang","permissions","typescript"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudflare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-19T18:04:11.000Z","updated_at":"2025-02-03T06:25:53.000Z","dependencies_parsed_at":"2023-01-14T16:59:15.976Z","dependency_job_id":"8c5be356-7226-45e9-a30e-e9c06cb1087f","html_url":"https://github.com/cloudflare/authr","commit_stats":{"total_commits":24,"total_committers":5,"mean_commits":4.8,"dds":0.375,"last_synced_commit":"3f6129d97d06e61033a7f237d84e35e678db490f"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fauthr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fauthr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fauthr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudflare%2Fauthr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudflare","download_url":"https://codeload.github.com/cloudflare/authr/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137891,"owners_count":21053775,"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":["access-control","authorization","golang","permissions","typescript"],"created_at":"2024-10-03T21:41:09.223Z","updated_at":"2025-04-10T01:14:52.070Z","avatar_url":"https://github.com/cloudflare.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# authr\n\n[![GO Build Status](https://github.com/cloudflare/authr/workflows/Golang%20Tests/badge.svg)](https://github.com/cloudflare/authr/actions?query=workflow%3A%22Golang+Tests%22)\n[![JS Build Status](https://github.com/cloudflare/authr/workflows/JavaScript%20Tests/badge.svg)](https://github.com/cloudflare/authr/actions?query=workflow%3A%22JavaScript+Tests%22)\n[![PHP Build Status](https://github.com/cloudflare/authr/workflows/PHP%20Tests/badge.svg)](https://github.com/cloudflare/authr/actions?query=workflow%3A%22PHP+Tests%22)\n\na flexible, expressive, language-agnostic access-control framework.\n\n## how it works\n\n_authr_ is an access-control framework. describing it as a \"framework\" is intentional because out of the box it is not going to automatically start securing your application. it is _extremely_ agnostic about quite a few things. it represents building blocks that can be orchestrated and put together in order to underpin an access-control system. by being so fundamental, it can fit almost any need when it comes to controlling access to specific resources in a particular system.\n\n### vocabulary\n\nthe framework itself has similar vocabulary to an [ABAC](https://en.wikipedia.org/wiki/Attribute-based_access_control) access-control system. the key terms are explained below.\n\n#### subject\n\na _subject_ in this framework represents an entity that is capable of performing actions; an _actor_ if you will. in most cases this will represent a \"user\" or an \"admin\".\n\n#### resource\n\na _resource_ represents an entity which can be acted upon. in a blogging application this might be a \"post\" or a \"comment\". those are things which can be acted upon by subjects wanting to \"edit\" them or \"delete\" them. it _is_ worth noting that subjects can also be resources — a \"user\" is something that can act and be acted upon.\n\na _resource_ has **attributes** which can be analyzed by authr. for example, a `post` might have an attribute `id` which is `333`. or, a user might have an attribute `email` which would be `person@awesome.blog`.\n\n#### action\n\nan _action_ is a simple, terse description of what action is being attempted. if say a \"user\" was attempting to fix a typo in their \"post\", the _action_ might just be `edit`.\n\n#### rule\n\na rule is a statement that composes conditions on resource and actions and specifies whether to allow or deny the attempt if the rule is matched. so, for example if you wanted to \"allow\" a subject to edit a private post, the JSON representation of the rule might look like this:\n\n```json\n{\n  \"access\": \"allow\",\n  \"where\": {\n    \"action\": \"edit\",\n    \"rsrc_type\": \"post\",\n    \"rsrc_match\": [[\"@type\", \"=\", \"private\"]]\n  }\n}\n```\n\nnotice the lack of anything that specifies conditions on _who_ is actually performing the action. this is important; more on that in a second.\n\n### agnosticism through interfaces\n\nacross implementations, _authr_ requires that objects implement certain functionality so that its engine can properly analyze resources against a list of rules that _belong_ to a subject.\n\nonce the essential objects in an application have implemented these interfaces, the essential question can finally be asked: **can this subject perform this action on this resource?**\n\n```php\n\u003c?php\n\nuse Cloudflare\\Authr;\n\nclass UserController extends Controller\n{\n    /** @var \\Cloudflare\\AuthrInterface */\n    private $authr;\n    ...\n\n    public function update(Request $req, Response $res, array $args)\n    {\n        // get the subject\n        $subject = $req-\u003egetActor();\n\n        // get the resource\n        $resource = $this-\u003egetUser($args['id']);\n\n        // check permissions!\n        if (!$this-\u003eauthr-\u003ecan($subject, 'update', $resource)) {\n            throw new HTTPException\\Forbidden('Permission denied!');\n        }\n\n        ...\n    }\n}\n```\n\n### forming the subject\n\n_authr_ is most of the time identifiable as an ABAC framework. it relies on the ability to place certain conditions on the attributes of resources. there is however one _key_ difference: **there is no way to specify conditions on the subject in rule statements.**\n\ninstead, the only way to specify that a specific actor is able to perform an action on a resource is to emit a rule from the returned list of rules that will match the action and allow it to happen. therefore, **a subject is only ever known as a list of rules.**\n\n```go\ntype Subject interface {\n    GetRules() ([]*Rule, error)\n}\n```\n\nand instead of the rules being statically defined somewhere and needing to make the framework worry about where to retrieve the rules from, **rules belong to subjects** and are only ever retrieved from the subject.\n\nwhen permissions are checked, the framework will simply call a method available via an interface on the subject to retrieve a list of rules for that specific subject. then, it will iterate through that list until it matches a rule and return a boolean based on whether the rule wanted to allow or deny.\n\n#### why disallow inspection of attributes on the actor?\n\nby reducing actors to just a list of rules, it condenses all of the logic about what a subject is capable of to a single area and keeps it from being scattered all over an application's codebase.\n\nalso, in traditional RBAC access-control systems, the notion of checking if a particular actor is in a certain \"role\" or checking the actors ID to determine access is incredibly brittle and \"ages\" a codebase.\n\nby having a single component which is responsible for answering the question of access-control, combined with being forced to clearly express what an actor can do with the authr rules, it leads to an incredible separation of concerns and a much more sustainable codebase.\n\neven if authr is not the access-control you choose, there is a distinct advantage to organizing access-control in your services this way, and authr makes sure that things stay that way.\n\n### expressing permissions across service boundaries\n\nbecause the basic unit of permission in authr is a rule defined in JSON, it is possible to let other services do the access-control checks for their own purposes.\n\nan example of this internally at Cloudflare is in a administrative service. by having this permissions defined in JSON, we can simply transfer all the rules down to the front-end (in JavaScript) and allow the front-end to hide/show certain functionality _based_ on the permission of whoever is logged in.\n\nwhen you can have the front-end and the back-end of a service seamlessly agreeing with each other on access-control by only updating a single rule, once, it can lead to much easier maintainability.\n\n## todo\n\n- [ ] create integration tests that ensure implementations agree with each other\n- [ ] finish go implementation\n- [ ] add examples of full apps using authr for access-contro\n- [ ] add documentation about the rules format\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflare%2Fauthr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudflare%2Fauthr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudflare%2Fauthr/lists"}