Core Concepts

Last updated: July 21st 2026

Access Policy

An access policy describes who may view protected content.

A policy row is exactly one of:

  • Element policyelementId set; applies to entries in that channel or structure when no element (or structure-parent) policy wins. Singles are not listed in General Access — set access on the single entry.
  • Section defaultsectionId set; applies to every entry in that channel with no element policy.
  • Category group defaultgroupId set; applies when no element (or structure-parent) policy wins.
  • Product type defaultproductTypeId set; applies when no element (or structure-parent) policy wins (requires Craft Commerce).

Never combine multiple scope columns on the same row.

Policy Principals

Principals are the audiences attached to a policy:

  • User group — everyone in the group gets access.
  • User — a specific Craft user gets access.

Built-in resolver types also include guest and public for the authorization engine. The current Control Panel editor focuses on groups and users; choosing Everyone removes the policy instead of storing a public principal.

Everyone vs Members Only

ModeStorageFront-end result
EveryoneNo policy for that element/scopeVisible to all visitors
Members onlyPolicy with selected groups/usersOnly matching logged-in members
Members only with no audiencesPolicy with zero principalsFail-closed — hidden from everyone

Resolution Order

For each element (after optional bypasses below):

  1. If an element policy exists → that policy decides visibility.
  2. Else if the element is in a Craft structure: walk parent → parent → … → top; the nearest ancestor with an element policy decides visibility.
  3. Else if a scope default exists (section / category group / product type) → that policy decides visibility.
  4. Else → public.

Step 2 applies to structure entries, categories, and Commerce products whose type uses a structure. Channel/single entries and flat product types skip it (no parents).

Built-in bypasses

These run before policy resolution when enabled in settings/config:

SettingEffect
Admins always have access (adminAlwaysAccess)Craft admin users see all protected content on the front end
Authors always have access (authorAlwaysAccess)Entry authors always see their own entries (entries only; not categories or products)

Control Panel requests always bypass filtering regardless of these settings.

The same order is used by:

  • Element query SQL filtering
  • Element sidebar summary
  • PHP AuthorizationService

Query-Level Authorization

Front-end Entry, Category, and (when Commerce is available) Product queries are modified before SQL runs. Unauthorized elements are never hydrated.

This applies automatically to:

  • Twig craft.entries / craft.categories / craft.products
  • PHP Entry::find() / Category::find() / Product::find()
  • GraphQL (and other consumers) that use those Craft element queries

Control Panel requests bypass filtering so editors can always manage content.

Fail Closed

If a policy exists but no principal matches the current visitor, access is denied. Empty audience lists are valid and mean “protected, nobody allowed yet.”