Skip to content

Spatie Laravel Permission

Documents the role:, permission:, and role_or_permission: middleware from spatie/laravel-permission — the authorization your routes require, surfaced in the spec.

Unlike every other integration, this one is off by default, even when the package is installed. Role and permission names are your application’s internal authorization taxonomy: invoices.approve, finance-admin, can-export-payroll. Publishing them puts a map of your internal structure into a document you may hand to customers, so Docuccino won’t do it unless you say so — per document:

// config/docuccino.php → documents.default.integrations
'permission' => ['enabled' => true],

Per document is the useful granularity. A partner-facing document can leave it off while your internal one turns it on, from the same codebase — see Multiple documents.

When the package is installed but the integration is left off, the build emits a single integration.disabled info diagnostic per document pointing you at the switch — so the opt-in is discoverable without publishing anything.

Once enabled, a route’s permission middleware is documented two ways:

  • a machine-readable x-permissions extension member on the operation, and
  • a human-readable line appended to the operation’s description — for example, “Requires permission: invoices.view”.
routes/api.php
Route::get('/invoices', [InvoiceController::class, 'index'])
->middleware('permission:invoices.view');

Every middleware form the package ships is recognized, including the ::using() FQCN style its own docs promote:

Middleware x-permissions entry Description line
role:admin { "type": "role", "values": ["admin"] } Requires role: admin
permission:invoices.view { "type": "permission", "values": ["invoices.view"] } Requires permission: invoices.view
role_or_permission:editor|invoices.edit { "type": "role_or_permission", "values": ["editor", "invoices.edit"] } Requires any of these roles or permissions: editor, invoices.edit
permission:invoices.view|invoices.manage { "type": "permission", "values": ["invoices.view", "invoices.manage"] } Requires any of these permissions: invoices.view, invoices.manage
permission:invoices.view,web { "type": "permission", "values": ["invoices.view"], "guard": "web" } Requires permission: invoices.view
PermissionMiddleware::using('invoices.view') Same as permission:invoices.view Same

A pipe-separated list is any-of — the caller needs any one of the listed roles or permissions, not all of them — so the wording says so explicitly rather than reading as a required set. An optional guard suffix is carried on the entry as a guard member, so a requirement scoped to a specific auth guard stays unambiguous.

A route carrying several of these middleware gets one x-permissions entry per middleware, in route order, and one description line each separated by a blank line.

An operation marked #[Unauthenticated] is skipped entirely: it documents no security requirement, so an authorization line beside security: [] would contradict itself.

The member is a list of objects, so tooling can consume it without parsing prose:

"x-permissions": [
{ "type": "role", "values": ["finance-admin"] },
{ "type": "permission", "values": ["invoices.approve", "invoices.manage"], "guard": "api" }
]
Field Type Meaning
type role | permission | role_or_permission Which middleware produced it
values array of strings The names demanded — any one of them satisfies the requirement
guard string, optional Present only when the middleware named a guard
Option Default Effect
enabled false Opt in to document role: / permission: / role_or_permission: requirements. Off by default so authorization names aren’t published unintentionally.

Beyond enabled, this integration has no options. It’s a no-op when the package isn’t installed, or when a route carries no matching middleware. See the configuration reference for the full integrations table.