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.
Opt-in — off by default
Section titled “Opt-in — off by default”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.
What it documents
Section titled “What it documents”Once enabled, a route’s permission middleware is documented two ways:
- a machine-readable
x-permissionsextension member on the operation, and - a human-readable line appended to the operation’s description — for example, “Requires permission: invoices.view”.
Route::get('/invoices', [InvoiceController::class, 'index']) ->middleware('permission:invoices.view');"get": { "description": "Requires permission: invoices.view", "x-permissions": [ { "type": "permission", "values": ["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.
Reading x-permissions
Section titled “Reading x-permissions”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 |
Configuration
Section titled “Configuration”| 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.