Payload CMS User Management | OpsBlu Docs

Payload CMS User Management

Payload CMS access control system covering collection-level and field-level permissions, auth strategies, and analytics data access patterns.

Payload CMS uses a code-first access control system where permissions are defined in TypeScript/JavaScript collection configs rather than through an admin UI. Every collection and global can have granular access functions that evaluate at runtime, receiving the authenticated user and the document being accessed. This gives Payload one of the most flexible permission models in the headless CMS space -- but it means permissions live in code, not in a database-driven role matrix.

Permission model

Payload's access control operates at four levels:

  • Collection-level access -- create, read, update, delete functions on each collection. Return true (allow all), false (deny all), or a query filter (allow matching documents only).
  • Field-level access -- individual fields can have their own access.read, access.create, access.update functions that override collection-level settings for that specific field.
  • Global-level access -- Globals (singleton documents like site settings) have read and update access functions.
  • Admin panel access -- the admin property on auth-enabled collections controls who can log into the Payload admin UI.

Access functions receive ({ req, id, data }) and can implement any logic: role checks, ownership verification, time-based access, IP restrictions, or external service calls.

Defining roles

Payload does not have built-in named roles. You define roles as values on a field in your auth collection:

// collections/Users.ts
const Users: CollectionConfig = {
  slug: 'users',
  auth: true,
  admin: {
    useAsTitle: 'email',
  },
  access: {
    admin: ({ req: { user } }) => user?.role === 'admin',
  },
  fields: [
    {
      name: 'role',
      type: 'select',
      options: ['admin', 'editor', 'analyst', 'viewer'],
      required: true,
      defaultValue: 'viewer',
    },
  ],
};

Common role patterns:

Role value Typical access Implementation pattern
admin Full CRUD on all collections, admin panel access access: () => true on all collections
editor Create/update content, no settings or user management Collection access returns true for content, false for settings
analyst Read reports and analytics data, no content editing read: () => true, create/update/delete: () => false
viewer Read-only access to published content read: ({ req }) => ({ _status: { equals: 'published' } })
api-client Programmatic access via API keys Auth strategy using API key header, scoped access functions

Admin UI paths

Since Payload is code-configured, "paths" refer to both admin panel routes and config file locations:

Task Location
Manage users Admin panel > Users collection (or your auth collection slug)
Define roles collections/Users.ts > fields array
Set collection permissions collections/[Name].ts > access property
Set field permissions fields array > individual field access property
Configure auth strategy collections/Users.ts > auth property
API key auth auth: { useAPIKey: true } in collection config
Admin panel access access.admin function in auth collection

API access management

Payload exposes REST and GraphQL APIs automatically for every collection:

REST API:

  • Endpoints at /api/[collection-slug] for CRUD operations
  • Authentication via cookie session, JWT Bearer token, or API key header
  • All access functions apply identically to REST and admin panel requests

GraphQL API:

  • Auto-generated schema at /api/graphql
  • Same access control as REST -- field-level access hides fields from the schema for unauthorized users
  • GraphQL introspection can be disabled in production

API Keys:

  • Enable with auth: { useAPIKey: true } on the auth collection
  • Each user gets an auto-generated API key visible in their profile
  • Pass via Authorization: users API-Key <key> header
  • Keys inherit the user's role and all associated access functions

Auth strategies (Payload 3.x):

  • Custom auth strategies for OAuth, SAML, LDAP
  • Configure in payload.config.ts under collections[].auth.strategies
  • Each strategy maps external identity claims to a local user record

Analytics-specific permissions

Payload's code-first model makes analytics permissions precise:

  • Analytics data collection -- if you store analytics events in a Payload collection, set access.read to allow analysts and access.create to allow only your ingestion service (check API key or IP).
  • Dashboard globals -- store analytics dashboard configuration in a Global with access.update restricted to admins and access.read open to analysts.
  • Tag management fields -- add tracking IDs (GA Measurement ID, GTM Container ID) as fields on a Settings global. Use field-level access to let marketing update tracking IDs without accessing other settings:
{
  name: 'gaMeasurementId',
  type: 'text',
  access: {
    update: ({ req }) => ['admin', 'analyst'].includes(req.user?.role),
  },
}
  • Content preview with analytics -- Payload's live preview feature can embed analytics dashboards. Control preview access via the admin.preview function.
  • Audit logging -- use Payload's afterChange and afterDelete hooks to log who modified analytics-related collections. Payload 3.x also supports the versions feature for full document history.

Sub-pages

  • Roles and Permissions -- access control function patterns, field-level permissions, and multi-tenant configurations
  • Adding and Removing Users -- user provisioning via admin panel and API, auth strategies, and deactivation patterns