{"id":19852516,"url":"https://github.com/thesoftwarehouse/react-router-permissions","last_synced_at":"2025-05-02T00:31:21.911Z","repository":{"id":35171505,"uuid":"180378911","full_name":"TheSoftwareHouse/react-router-permissions","owner":"TheSoftwareHouse","description":"react-router-permissions - abstraction layer for handling authorization with react-router","archived":false,"fork":false,"pushed_at":"2022-12-09T23:26:07.000Z","size":1551,"stargazers_count":18,"open_issues_count":40,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-15T07:19:38.023Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/TheSoftwareHouse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-09T13:57:09.000Z","updated_at":"2023-07-18T14:20:58.000Z","dependencies_parsed_at":"2023-01-15T15:15:21.932Z","dependency_job_id":null,"html_url":"https://github.com/TheSoftwareHouse/react-router-permissions","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheSoftwareHouse%2Freact-router-permissions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheSoftwareHouse%2Freact-router-permissions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheSoftwareHouse%2Freact-router-permissions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheSoftwareHouse%2Freact-router-permissions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheSoftwareHouse","download_url":"https://codeload.github.com/TheSoftwareHouse/react-router-permissions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251966431,"owners_count":21672666,"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":[],"created_at":"2024-11-12T14:03:14.564Z","updated_at":"2025-05-02T00:31:16.902Z","avatar_url":"https://github.com/TheSoftwareHouse.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Status\n\n[![Build Status](https://travis-ci.org/TheSoftwareHouse/react-router-permissions.svg?branch=master)](https://travis-ci.org/TheSoftwareHouse/react-router-permissions) [![Code Coverage](https://codecov.io/gh/TheSoftwareHouse/react-router-permissions/branch/master/graph/badge.svg)](https://codecov.io/gh/TheSoftwareHouse/react-router-permissions) [![License](https://img.shields.io/npm/l/@tshio/react-router-permissions.svg)](https://github.com/TheSoftwareHouse/react-router-permissions/blob/master/LICENSE.md) [![Version](https://img.shields.io/npm/v/@tshio/react-router-permissions.svg)](https://www.npmjs.com/package/@tshio/react-router-permissions)\n\n# react-router-permissions\n\n## Installation\n\nUsing [yarn](https://yarnpkg.com/lang/en/):\n\n    $ yarn add @tshio/react-router-permissions\n\nUsing [npm](https://www.npmjs.com/):\n\n    $ npm install --save @tshio/react-router-permissions\n\n## Usage\n\nGoal of this package is to provide abstraction layer for handling authorization with react-router.\nThe only requirement for `AuthorizedRoute` to work is to have any kind `Router` and at least one `PermissionsProvider`\nhigher in your component tree.\n\nA [codesandbox example](https://codesandbox.io/s/github/TheSoftwareHouse/react-router-permissions/tree/master/example/) is available.\n\n[![Edit React Router Permissions - Basic Usage](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/TheSoftwareHouse/react-router-permissions/tree/master/example/?fontsize=14)\n\n```js\nimport React from 'react';\nimport { createStore } from 'redux';\nimport { Provider } from 'react-redux';\nimport { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom';\n\nconst store = createStore(state =\u003e ({ ...state }), {\n  authorization: {\n    roles: ['USER', 'ADMIN'],\n  },\n});\n\nconst authorizationStrategy = (roles, requirement) =\u003e {\n  return roles.find(role =\u003e role === requirement);\n};\n\n// it's possible to override strategy for single route\nconst loginAuthorizationStrategy = (roles, requirement) =\u003e {\n  return roles \u0026\u0026 roles.length;\n};\n\nclass App extends React.Component {\n  render() {\n    return (\n      \u003cProvider store={store}\u003e\n        \u003cPermissionsProvider\n          permissions={store.getState().authorization.roles}\n          authorizationStrategy={permissionsStrategy}\n        \u003e\n          \u003cBrowserRouter\u003e\n            \u003cSwitch\u003e\n              \u003cAuthorizedRoute path=\"/login\" authorizationStrategy={loginAuthorizationStrategy}\u003e\n                {({ isAuthorized }) =\u003e (isAuthorized ? \u003cLogin /\u003e : \u003cRedirect to=\"/home\" /\u003e)}\n              \u003c/AuthorizedRoute\u003e\n              \u003cRoute path=\"/home\" component={Home} /\u003e\n              \u003cAuthorizedRoute path=\"/users\" requires=\"ADMIN\"\u003e\n                {({ isAuthorized }) =\u003e (isAuthorized ? \u003cUsers /\u003e : \u003cRedirect to=\"/home\" /\u003e)}\n              \u003c/AuthorizedRoute\u003e\n            \u003c/Switch\u003e\n          \u003c/BrowserRouter\u003e\n        \u003c/PermissionsProvider\u003e\n      \u003c/Provider\u003e\n    );\n  }\n}\n```\n\n`authorizationStrategy` is a function that gets called each time user either tries to access authorized content. It is called\nwith `permissions` passed to `PermissionsProvider` as first argument and `requirement` passed to `AuthorizedRoute` as second.\nIt's result is stored in isAuthorized property on ChildrenAsFunction Function used by `AuthorizedRoute`.\n\nUser is not bound to using role base authorization strategies. To showcase that we would need to make following changes to our example:\n\n```js\nconst store = createStore(\n  state =\u003e ({...state}), {\n    authorization: {\n      permissions: {\n        \"access-home\": true,\n        \"access-users-list\": false,\n      },\n     }\n  });\n\nconst authorizationStrategy = (permissions, requirement) =\u003e {\n  return permissions[requirement];\n};\n\n...\n\u003cPermissionsProvider\n  permissions={store.getState().authorization.permissions}\n  authorizationStrategy={permissionsStrategy}\n\u003e\n\n...\n\n\u003cAuthorizedRoute\n  path='/users'\n  requires='access-users-list'\n\u003e\n```\n\nThere are some strategies provided with the package out of the box. Those are:\n\n- Role based strategy\n\n  ```js\n  const permissions = ['MODERATOR', 'PREMIUM_USER'];\n\n  ...\n  // authorization will pass\n  \u003cAuthorizedRoute\n    path='/authorized-section'\n    requires='MODERATOR'\n  \u003e\n  ...\n\n  ...\n  // authorization will fail\n  \u003cAuthorizedRoute\n    path='/authorized-section'\n    requires='ADMIN'\n  \u003e\n  ...\n  ```\n\n* Permissions based strategy\n\n  ```js\n  const permissions = {\n    canReadPosts: true,\n    canManagePosts: true,\n    canManageUsers: false,\n  };\n\n  ...\n  // authorization will pass\n  \u003cAuthorizedRoute\n    path='/authorized-section'\n    requires='canManagePosts'\n  \u003e\n  ...\n\n  ...\n  // authorization will fail\n  \u003cAuthorizedRoute\n    path='/authorized-section'\n    requires='canManageUsers'\n  \u003e\n  ...\n  ```\n\n* At least one strategy\n\n  ```js\n  const permissions = {\n    canReadPosts: true,\n    canManagePosts: false,\n    canManageUsers: false,\n    canViewUsers: false,\n  };\n\n  ...\n  // authorization will pass\n  \u003cAuthorizedRoute\n    path='/authorized-section'\n    requires={['canReadPosts', 'canManagePosts']}\n  \u003e\n  ...\n\n  ...\n  // authorization will fail\n  \u003cAuthorizedRoute\n    path='/authorized-section'\n    requires={['canManageUsers', 'canViewUsers']}\n  \u003e\n  ...\n  ```\n\nWe also provide authorized section to cover cases where we need authorization but want to be route agnostic\n\n```js\nclass Home extends React.Component {\n  render() {\n    return (\n      \u003cFragment\u003e\n        \u003cHeader /\u003e\n        \u003cAuthorizedSection requires=\"ADMIN\"\u003e\n          {({ isAuthorized }) =\u003e (isAuthorized ? \u003cUsers /\u003e : null)}\n        \u003c/AuthorizedSection\u003e\n      \u003c/Fragment\u003e\n    );\n  }\n}\n```\n\nThis works exactly like AuthorizedRoute but will attempt access regardless of active route.\n\nSince permissions are being fetched from context, it is possible to override them for certain section of our application\nusing nested `PermissionsProvider`. Result of `authorizationStrategy` does not need to be boolean too.\nWhile most of the time it being a boolean might be convenient. It is possible for `authorizationStrategy`\nto return complex object that we can utilize in our component.\n\n```js\nconst store = createStore(\n  state =\u003e ({...state}), {\n    permissions: {\n      ...,\n      \"nested-permissions\": {\n        \"user-name\": {\n          create: true,\n          read: true,\n          update: false,\n          delete: false,\n        }\n      },\n      ...,\n    }\n  });\n\nconst authorizationStrategy = (permissions, requirement) =\u003e {\n  return permissions[requirement];\n};\n\nclass Header extends React.Component {\n  render() {\n    return (\n      \u003cPermissionsProvider\n        permissions={store.getState().permissions[`nested-permissions`]}\n        authorizationStrategy={permissionsStrategy}\n      \u003e\n        \u003cAuthorizedSection\n          requires='user-name'\n        \u003e\n          {({isAuthorized}) =\u003e (\n            isAuthorized.read ? (\n              \u003cFragment\u003e\n              \u003ch4\u003e\n                Name\n              \u003c/h4\u003e\n              \u003cspan\u003e\n                Matt Murdock\n              \u003c/span\u003e\n                {isAuthorized.create \u0026\u0026 (\n                  \u003cbutton\u003eAdd\u003c/button\u003e\n                )}\n                {isAuthorized.delete \u0026\u0026 (\n                  \u003cbutton\u003eDelete\u003c/button\u003e\n                )}\n            \u003c/Fragment\u003e\n            ) : null\n          )}\n        \u003c/AuthorizedSection\u003e\n      \u003c/PermissionsProvider\u003e\n    );\n  }\n}\n```\n\nWe decided to use hooks in our library. Therefore, we are introducing 2 our hooks: `useAuthorize` which one is returning a value of authorization.\n\n```js\nexport const AdminSection = ({ requires, authorizationStrategy }) =\u003e {\n  const isAuthorized = useAuthorize(requires, authorizationStrategy);\n\n  return isAuthorized ? \u003ch2\u003eAdmin New's\u003c/h2\u003e : null;\n};\n```\n\nSecond hook is `usePermission` which one is returning an object with `permissions` and `authorizationStrategy` from the nearest `PermissionsProvider`.\n\n```js\nexport const PermissionsRoles = () =\u003e {\n  const { permissions } = usePermissions();\n  return \u003cspan\u003eRoles length: {permissions.length} \u003c/span\u003e;\n};\n```\n\n## Config options\n\n### PermissionsProvider\n\n| Property name         | Type                              | Required | Description                                                                                                                      |\n| --------------------- | --------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |\n| permissions           | `Array or Object`                 | `true`   | Permissions granted to user throughout the application. Can take any shape or form                                               |\n| authorizationStrategy | `(permissions, requirement) =\u003e *` | `true`   | Function that is aware of permissions format and is called for each authorization attempt with permissions and given requirement |\n\n### AuthorizedRoute\n\n| Property name         | Type                              | Required | Description                                                                                           |\n| --------------------- | --------------------------------- | -------- | ----------------------------------------------------------------------------------------------------- |\n| path                  | `string`                          | `true`   | Path that when accessed in by browser, will trigger authorization attempt                             |\n| requires              | `*`                               | `false`  | Requirement that will be used in access attempt call                                                  |\n| authorizationStrategy | `(permissions, requirement) =\u003e *` | `false`  | Function that if passed will override `authorizationStrategy` passed to nearest `PermissionsProvider` |\n\n### AuthorizedSection\n\n| Property name         | Type                              | Required | Description                                                                                           |\n| --------------------- | --------------------------------- | -------- | ----------------------------------------------------------------------------------------------------- |\n| requires              | `*`                               | `true`   | Requirement that will be used in access attempt call                                                  |\n| authorizationStrategy | `(permissions, requirement) =\u003e *` | `false`  | Function that if passed will override `authorizationStrategy` passed to nearest `PermissionsProvider` |\n\n### Hooks\n\n| Hook's name    | Arguments                                    | Description                                                                                                               |\n| -------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |\n| usePermissions | `null`                                       | Returns context of nearest Permissions Provider                                                                           |\n| useAuthorize   | `(requirement, authorizationStrategy?) =\u003e *` | Returns a value of authorization. AuthorizationStrategy argument is optional. If passed, will override existing strategy. |\n\n## Development\n\nWe welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/TheSoftwareHouse/react-router-permissions/blob/master/CONTRIBUTING.md) first.\nYou can submit any ideas as [GitHub issues](https://github.com/TheSoftwareHouse/react-router-permissions/issues).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthesoftwarehouse%2Freact-router-permissions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthesoftwarehouse%2Freact-router-permissions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthesoftwarehouse%2Freact-router-permissions/lists"}