This is the legacy documentation of Project-level Custom Applications, which is in maintenance mode. Visit the new documentation for Org-level Custom Applications.
User Permissions
The Merchant Center allows configuring permissions based on a user’s team. Teams belong to an organization and users can be member of multiple teams.
See User Permission Concepts for more information about the relationships between users, teams, and organizations.
Types of permissions
The Merchant Center exposes different types of user permissions that are bound to a project and can be used within a Custom Application code. For example, to restrict access to a view, to prevent updating or deleting certain resources, etc.
General permissions
General permissions are bound to a resource and grant either view or manage access.
A manage access always implies view access as well.
A general permission is represented as a string, with the resource name prefixed by View
or Manage
. The following resource names are currently supported:
Products
Categories
Customers
CustomerGroups
Orders
ProductDiscounts
CartDiscounts
DiscountCodes
ProjectSettings
ProductTypes
DeveloperSettings
Some examples are: ViewProducts
, ManageOrders
, etc.
Action rights
Action rights can be used to refine the general permissions. For example, manage access to products can be limited to exclude publishing.
An action right is represented as an object with the shape { group: string, name: string }
. The group
relates to the permission while the name
is the action right itself. Currently the following action rights for the group: 'products'
exist:
PublishProducts
UnpublishProducts
AddPrices
EditPrices
DeletePrices
DeleteProducts
AddProducts
Using configured permissions within a Custom Application
The @commercetools-frontend/permissions
package should be used to implement and apply the user permissions for the specific parts of the Custom Applications. The package exposes React components and React hooks to make it easy to work with it:
useIsAuthorized()
injectAuthorized()
<RestrictedByPermissions>
Supported named arguments
demandedPermissions
: an array of general permissions.demandedAtionRights
: (optional) an array of action rights.
Usage
import { PERMISSIONS } from './constants/permissions.js';const ExampleComponent = () => {const canManageProducts = useIsAuthorized({demandedPermissions: [PERMISSIONS.ManageProducts],});return <span>{ canManageProducts ? 'Authorized' : 'Not authorized' }</span>;};
Supported arguments
demandedPermissions
: an array of demanded general permissions.options
(optional)actionRights
: (optional) an array of action rights.
propName
: (optional) the name of the injected prop (default toisAuthorized
).
Usage
const InputField = props => (<Inputdisabled={!props.isAuthorized}/>);export default injectAuthorized([PERMISSIONS.ViewProducts])(InputField);
<RestrictedByPermissions>
A React component that evaluates the demanded permissions against the user permissions and renders the result as a function with the named argument isAuthorized
.
Supported props
permissions
: an array of demanded general permissions.actionRights
: (optional) an array of demanded action rights.unauthorizedComponent
: (optional) a React component instance to be rendered in case the evaluation of the permissions returnsfalse
. This happens the permissions do not match.render
: (optional) a render prop function that should return a React node. The function is called with the named boolean argumentisAuthorized
.children
: (optional) a render prop function that should return a React node. The function is called with the named boolean argumentisAuthorized
.
Usage
<RestrictedByPermissions permissions={[PERMISSIONS.ManageOrders]} unauthorizedComponent={Unauthorized}><MyAuthorizedComponent /></RestrictedByPermissions><RestrictedByPermissions permissions={[PERMISSIONS.ManageOrders]}{({ isAuthorized }) => <button disabled={!isAuthorized}>My button</button>}</RestrictedByPermissions>
Best practices
Using a file with constants
It is recommended to store general permissions and action rights used by your application into a permissions.js
file. This helps to avoid repeating permission names across your code base and preventing typographical errors while giving an overview of used permissions in an application easily.
export const ACTION_RIGHTS = {PublishProducts: { group: 'products', name: 'PublishProducts' },};export const PERMISSIONS = {ManageOrders: 'ManageOrders'}
Evaluate permissions separately
It is recommended to evaluate each permission separately even if the respective APIs allow specifying an array of general permissions and action rights. Combining different permissions in one hook or component usage can become hard to reason about. Splitting and later joining resulting booleans helps to keep the implications of permissions easier to understand.
// Instead ofconst canManageProductsAndViewOrders = useIsAuthorized({demandedPermissions: [PERMISSIONS.ViewOrders, PERMISSIONS.ManageProducts],});// Apply the hook twice...const canManageProducts = useIsAuthorized({demandedPermissions: [PERMISSIONS.ManageProducts],});const canViewOrders = useIsAuthorized({demandedPermissions: [PERMISSIONS.ViewOrders],});// ...and compose the resulting booleansconst canManageProductsAndViewOrders = canManageProducts && canViewOrders;