Skip to main content

Define custom permissions

Vendure uses a fine-grained access control system based on roles & permissions. This is described in detail in the Auth guide. The built-in Permission enum includes a range of permissions to control create, read, update, and delete access to the built-in entities.

When building plugins, you may need to define new permissions to control access to new functionality. This guide explains how to do so.

Defining a single permission

For example, let's imagine you are creating a plugin which exposes a new mutation that can be used by remote services to sync your inventory. First of all we will define the new permission using the PermissionDefinition class:

src/plugins/inventory-sync/constants.ts
import { PermissionDefinition } from '@vendure/core';

export const sync = new PermissionDefinition({
name: 'SyncInventory',
description: 'Allows syncing stock levels via Admin API'
});

This permission can then be used in conjuction with the @Allow() decorator to limit access to the mutation:

src/plugins/inventory-sync/api/inventory-sync.resolver.ts
import { Mutation, Resolver } from '@nestjs/graphql';
import { Allow } from '@vendure/core';
import { sync } from '../constants';

@Resolver()
export class InventorySyncResolver {

@Allow(sync.Permission)
@Mutation()
syncInventory(/* ... */) {
// ...
}
}

Finally, the sync PermissionDefinition must be passed into the VendureConfig so that Vendure knows about this new custom permission:

src/plugins/inventory-sync/inventory-sync.plugin.ts
import gql from 'graphql-tag';
import { VendurePlugin } from '@vendure/core';

import { InventorySyncResolver } from './api/inventory-sync.resolver'
import { sync } from './constants';

@VendurePlugin({
adminApiExtensions: {
schema: gql`
input InventoryDataInput {
# omitted for brevity
}

extend type Mutation {
syncInventory(input: InventoryDataInput!): Boolean!
}
`,
resolvers: [InventorySyncResolver]
},
configuration: config => {
config.authOptions.customPermissions.push(sync);
return config;
},
})
export class InventorySyncPlugin {}

On starting the Vendure server, this custom permission will now be visible in the Role detail view of the Admin UI, and can be assigned to Roles.

Custom CRUD permissions

Quite often your plugin will define a new entity on which you must perform create, read, update and delete (CRUD) operations. In this case, you can use the CrudPermissionDefinition which simplifies the creation of the set of 4 CRUD permissions.

For example, let's imagine we are creating a plugin which adds a new entity called ProductReview. We can define the CRUD permissions like so:

src/plugins/product-review/constants.ts
import { CrudPermissionDefinition } from '@vendure/core';

export const productReview = new CrudPermissionDefinition('ProductReview');

These permissions can then be used in our resolver:

src/plugins/product-review/api/product-review.resolver.ts
import { Mutation, Resolver } from '@nestjs/graphql';
import { Allow, Transaction } from '@vendure/core';
import { productReview } from '../constants';

@Resolver()
export class ProductReviewResolver {

@Allow(productReview.Read)
@Query()
productReviews(/* ... */) {
// ...
}

@Allow(productReview.Create)
@Mutation()
@Transaction()
createProductReview(/* ... */) {
// ...
}

@Allow(productReview.Update)
@Mutation()
@Transaction()
updateProductReview(/* ... */) {
// ...
}

@Allow(productReview.Delete)
@Mutation()
@Transaction()
deleteProductReview(/* ... */) {
// ...
}
}

Finally, the productReview CrudPermissionDefinition must be passed into the VendureConfig so that Vendure knows about this new custom permission:

src/plugins/product-review/product-review.plugin.ts
import gql from 'graphql-tag';
import { VendurePlugin } from '@vendure/core';

import { ProductReviewResolver } from './api/product-review.resolver'
import { productReview } from './constants';

@VendurePlugin({
adminApiExtensions: {
schema: gql`
# omitted for brevity
`,
resolvers: [ProductReviewResolver]
},
configuration: config => {
config.authOptions.customPermissions.push(productReview);
return config;
},
})
export class ProductReviewPlugin {}