Payload comes with open-ended access control. You can define whatever type of pattern that you can dream up, and best of all—it's all done with simple JavaScript.
A common pattern is Role-Based Access Control. Here, we'll walk you through how to create your own RBAC pattern on both the collection-level and field-level.
In more detail, here are the pieces that we will be building:
role
fieldWe'll be using create-payload-app
to build out the initial project.
npx create-payload-app payload-rbac
javascript
for languageblank
for our templateThis will give us a simple project with a Payload config and Users collection. The structure of the project will be:
First, we will add the role
field to our Users collection with 2 options: admin
and user
.
Next, we will create a new Orders.js
collection in our collections/
directory and scaffold out basic fields and values - including the createdBy
relationship to the user.
The Orders collection has an array
field for items and a createdBy
field which is a relationship to our Users
collection. The createdBy
field will feature a strict update
access control function so that it can never be changed.
Notice we also have a condition
function under the createdBy
field's access. This will hide createdBy
until it has a value.
createdBy
Attribute Using a HookNext, we'll add a hook that will run before any order is created. This is done by adding a beforeChange
hook to our collection definition.
The logic in this hook sets the createdBy
field to be the current user's id
value, only if it is on a create
operation. This will create a relationship between an order and the user who created it.
Next, the access control for the collection can be defined. Payload's access control is based on functions. An access control function returns either a boolean
value to allow/disallow access or it returns a query constraint that filters the data.
We want our function to handle a few scenarios:
Once defined, this function is added to the access
property of the collection definition:
With this function added to the read
, update
, and delete
access properties, the function will run whenever these operations are attempted on the collection.
The last step is to add the collection to our payload.config.js
Let's verify the functionality:
Start up the project by running npm run dev
or yarn dev
and navigate to http://localhost:3000/admin
Create your initial user with the admin
role.
Create an Order with the admin
user.
Create an additional user with the user
role by navigating to the Users collection, selecting Create New, entering an email/password, then saving.
Log out of your admin
user by selecting the icon in the bottom left, then log in with the second user.
You'll notice if we go to the Orders collection, no Orders will be shown. This indicates that the access control is working properly.
Create another Order. Note that the current user will be saved to Created By
in the sidebar.
Navigate back to Orders list on the dashboard. There will only be the single order created by the current user.
Log out, then back in with your admin
user. You should be able to see the original Order as well as the Order created by the second user.
With everything working at the collection level, we can carry the concepts further and see how they can be applied at the field level. Suppose we wanted to add a paymentID
field only for Admin users. Create an isAdmin
function that checks the role as we did earlier.
Add a new field to Orders and set create
, read
or update
access calls to use the isAdmin function.
The new paymentID field is not available to the users even on one's own Order. Field level access controls allow for greater granularity over document level access for Collections and Globals. This shows how easy it is to manage exact permissions throughout the admin UI, GraphQL and REST endpoints; it even works when querying relationships to keep data secure.
Now that we have a basic example working. What are some ways that this could be improved?
editor
role which allows reading and editing, but disallows creating. This all can be customized specifically to your needs.I hope you enjoyed the introduction to doing role-based access control with Payload!
Come join the Payload discussions on GitHub.