Back to Payload

Access Control

docs/access-control/overview.mdx

3.84.14.4 KB
Original Source
<YouTube id="DoPLyXG26Dg" title="Overview of Payload Access Control" />

Access Control determines what a user can and cannot do with any given Document, as well as what they can and cannot see within the Admin Panel. By implementing Access Control, you can define granular restrictions based on the user, their roles (RBAC), Document data, or any other criteria your application requires.

Access Control functions are scoped to the operation, meaning you can have different rules for create, read, update, delete, etc. Access Control functions are executed before any changes are made and before any operations are completed. This allows you to determine if the user has the necessary permissions before fulfilling the request.

There are many use cases for Access Control, including:

  • Allowing anyone read access to all posts
  • Only allowing public access to posts where a status field is equal to published
  • Giving only users with a role field equal to admin the ability to delete posts
  • Allowing anyone to submit contact forms, but only logged in users to read, update or delete them
  • Restricting a user to only be able to see their own orders, but no-one else's
  • Allowing users that belong to a certain organization to access only that organization's resources

There are three main types of Access Control in Payload:

Default Access Control

Payload provides default Access Control so that your data is secured behind Authentication without additional configuration. To do this, Payload sets a default function that simply checks if a user is present on the request. You can override this default behavior by defining your own Access Control functions as needed.

Here is the default Access Control that Payload provides:

ts
const defaultPayloadAccess = ({ req: { user } }) => {
  // Return `true` if a user is found
  // and `false` if it is undefined or null
  return Boolean(user) // highlight-line
}
<Banner type="warning"> **Important:** In the [Local API](../local-api/overview), all Access Control is _skipped_ by default. This allows your server to have full control over your application. To opt back in, you can set the `overrideAccess` option to `false` in your requests. </Banner>

The Access Operation

The Admin Panel responds dynamically to your changes to Access Control. For example, if you restrict editing ExampleCollection to only users that feature an "admin" role, Payload will hide that Collection from the Admin Panel entirely. This is super powerful and allows you to control who can do what within your Admin Panel using the same functions that secure your APIs.

To accomplish this, Payload exposes the Access Operation. Upon login, Payload executes each Access Control function at the top level, across all Collections, Globals, and Fields, and returns a response that contains a reflection of what the currently authenticated user can do within your application.

<Banner type="warning"> **Important:** When your access control functions are executed via the [Access Operation](../authentication/operations#access), the `id`, `data`, `siblingData`, `blockData` and `doc` arguments will be `undefined`. Additionally, `Where` queries returned from access control functions will not be run - we'll assume the user does not have access instead.

This is because Payload is executing your functions without referencing a specific Document.

</Banner>

If you use id, data, siblingData, blockData and doc within your access control functions, make sure to check that they are defined first. If they are not, then you can assume that your Access Control is being executed via the Access Operation to determine solely what the user can do within the Admin Panel.

Locale Specific Access Control

To implement locale-specific access control, you can use the req.locale argument in your access control functions. This argument allows you to evaluate the current locale of the request and determine access permissions accordingly.

Here is an example:

ts
const access = ({ req }) => {
  // Grant access if the locale is 'en'
  if (req.locale === 'en') {
    return true
  }

  // Deny access for all other locales
  return false
}