← Back to articles

June 3, 2026

8 min read

Permissions and Roles in Strapi: A Secure Structure from Day One

How to configure the Strapi RBAC system for projects with multiple user types, protect routes and fields, and avoid common access control mistakes.

Leer en espanol

The Strapi RBAC system and its two layers

Strapi has two separate permission systems: the Content API (for frontend users or API clients) and the Admin Panel (for editors and administrators using the Strapi interface). They are independent and configured separately. An API user has no access to the admin, and vice versa.

The Content API system uses roles: Public (no authentication) and Authenticated (with JWT). In Strapi v4 and v5 with the free license, these are the only two roles available for the API. The Enterprise license adds granular RBAC for the Content API. For most projects, differentiation is achieved with custom middleware rather than additional roles.

What each role can access and how to adjust it

The Public role should have access to no endpoints by default. A common mistake is leaving Public with find and findOne permissions on collections that require authentication. Strapi restricts nothing by default — you must explicitly configure what each role can do in Settings > Roles.

The Authenticated role has access to what is explicitly granted. For an ecommerce, authenticated users can view their own orders and update their profile, but should not be able to view other users orders. That restriction cannot be achieved with the role system alone — it requires middleware that filters by the authenticated user.

  • Audit the Public role at project start: it should have no more permissions than necessary.
  • Use Authenticated only for endpoints that require login.
  • Document which endpoints are public and why, so the decision is explicit.

Custom middleware for specific access logic

When access logic goes beyond authenticated/unauthenticated — for example, "only the resource owner can modify it" — custom middleware is needed. In Strapi, that middleware is added at the route level in the API routes file.

The most common pattern is verifying that the authenticated user ID matches the `author` field of the resource before running the controller. If it does not match, return a 403 before the controller accesses the database.

Ownership verification middleware for Content API routes.

// src/middlewares/is-owner.js
module.exports = (config, { strapi }) => {
  return async (ctx, next) => {
    const { id } = ctx.params;
    const userId = ctx.state.user?.id;

    if (!userId) {
      return ctx.unauthorized('Authentication required');
    }

    const entity = await strapi.entityService.findOne(
      config.contentType,
      id,
      { populate: { author: { fields: ['id'] } } },
    );

    if (!entity || entity.author?.id !== userId) {
      return ctx.forbidden('Access denied');
    }

    await next();
  };
};

Common mistakes when configuring Strapi permissions

The most frequent mistake is relying only on the panel role system without validating ownership in middleware. An authenticated user with access to the update endpoint can modify any record if no additional check exists. Strapi does not perform that check automatically.

Another mistake is not reviewing permissions after adding a new content type. When a new collection is created, its endpoints have no permissions by default. But if a role has broad permissions configured, the new collection may be accessible unintentionally. Reviewing roles after every model change prevents data leaks.

More articles

Back to articles