Skip to main content

How It Works

Startup

When Strapi starts with plugin-api-permissions enabled, the plugin:

  1. Extends the user content type with a roles manyToMany relation pointing to plugin::api-permissions.role. This is done dynamically — no manual schema change is required.
  2. Registers a content-api authentication strategy with Strapi's authentication system. This strategy runs before every Content API request.
  3. Seeds the database with a Public and an Authenticated role if none exist yet.

Per-request flow

For every incoming Content API request, the authentication strategy:

  1. Calls the registered session resolver with the Koa context, passing the full request object.
  2. Resolves the roles:
    • If the resolver returns null → uses the Public role.
    • If the resolver returns { user, roles } → uses the returned roles, plus the Authenticated role as a baseline.
  3. Loads permissions for all resolved roles from the database.
  4. Builds a CASL ability from those permissions and attaches it to the request context.
  5. Strapi's route middleware checks the ability before executing the controller.

Permission model

Each permission record stores:

  • action — one of find, findOne, create, update, delete, or a plugin-specific action string.
  • subject — the UID of the content type or plugin endpoint (e.g. api::article.article).
  • role — the role this permission belongs to.

CASL uses the (action, subject) pair to determine whether a request is allowed.

Role inheritance

There is no role inheritance. Each role's permissions are independent. If a user has multiple roles, the union of all permissions from all roles is applied.

Middleware integration

The plugin registers a global middleware on all Content API routes. This middleware:

  1. Checks if the route requires authentication.
  2. If yes, verifies the CASL ability built from the resolved roles.
  3. Returns 403 Forbidden if the ability does not permit the action.

Diagram

Incoming Content API Request


Session Resolver (your code)


Resolve Roles (DB lookup)


Build CASL Ability (permissions)


Strapi Route Middleware

┌─────┴─────┐
Allowed? No → 403 Forbidden


Controller runs