Configuration
The published config/permissions.php in full:
return [
'models' => [
'role' => RoundlyConsulting\Permissions\Models\Role::class,
'permission' => RoundlyConsulting\Permissions\Models\Permission::class,
],
'table_names' => [
'roles' => 'roles',
'permissions' => 'permissions',
'permission_role' => 'permission_role',
'model_roles' => 'model_roles',
'model_permissions' => 'model_permissions',
'role_assignments' => 'role_assignments',
'permission_assignments' => 'permission_assignments',
],
'key_type' => env('PERMISSIONS_KEY_TYPE', 'bigint'),
'register_gate_check' => true,
'assignments' => [
'enabled' => env('PERMISSIONS_ASSIGNMENTS', false),
'scope_key_type' => env('PERMISSIONS_SCOPE_KEY_TYPE'),
'global_applies_in_scope' => env('PERMISSIONS_GLOBAL_APPLIES_IN_SCOPE', true),
],
'description_fallback' => env('PERMISSIONS_DESCRIPTION_FALLBACK', RoundlyConsulting\Translatable\Enums\FallbackMode::Fallback),
'cache' => [
'store' => env('PERMISSIONS_CACHE_STORE', 'default'),
'key' => 'permissions.cache',
'ttl' => env('PERMISSIONS_CACHE_TTL', 300), // seconds (at least 1)
],
];Every key
| Key | Default | Env | Purpose |
|---|---|---|---|
models.role | Role::class | — | Role model; swap for a subclass to extend it. Anything else throws InvalidConfigurationException. |
models.permission | Permission::class | — | Permission model; swap for a subclass. Anything else throws InvalidConfigurationException. |
table_names.roles | roles | — | Roles table. |
table_names.permissions | permissions | — | Permissions table. |
table_names.permission_role | permission_role | — | Role ↔ permission pivot. |
table_names.model_roles | model_roles | — | Holder ↔ role polymorphic pivot. |
table_names.model_permissions | model_permissions | — | Holder ↔ permission polymorphic pivot. |
table_names.role_assignments | role_assignments | — | Scoped and time-boxed role grants (2.1). |
table_names.permission_assignments | permission_assignments | — | Scoped and time-boxed direct permissions (2.1). |
key_type | bigint | PERMISSIONS_KEY_TYPE | Holder key type — bigint, uuid or ulid. Types model_id; set before you migrate. Unset or blank reads as bigint; any other value throws InvalidConfigurationException. |
register_gate_check | true | — | Register the Gate::before hook so can:<permission> resolves. Accepts true/false, 1/0, on/off, yes/no; blank is not set, so true applies; anything else throws InvalidConfigurationException at boot. |
assignments.enabled | false | PERMISSIONS_ASSIGNMENTS | Scoped and time-boxed grants and owned roles. Off: nothing reads the 2.1 tables or columns — the package sends exactly the 2.0 queries — and every scoped or time-boxed call throws PermissionException. A strict boolean, like register_gate_check. |
assignments.scope_key_type | key_type | PERMISSIONS_SCOPE_KEY_TYPE | Key type of your scope and role-owner models — bigint, uuid or ulid. Types scope_id and roles.owner_id; not set reads as key_type. Set it before you migrate; an unknown value throws InvalidConfigurationException. |
assignments.global_applies_in_scope | true | PERMISSIONS_GLOBAL_APPLIES_IN_SCOPE | Whether an unscoped grant also counts inside a scope — an admin is an admin in every project. Strict multi-tenant apps set it to false. |
description_fallback | Fallback | PERMISSIONS_DESCRIPTION_FALLBACK | How the translatable description falls back — Fallback, None or Any. A case or its string value (fallback, none, any); blank is not set, so Fallback applies; an unknown value throws InvalidConfigurationException instead of reading as Fallback. |
cache.store | default | PERMISSIONS_CACHE_STORE | Cache store for the catalog; default — or a blank value, which is not set — uses the app’s default store. A non-string value throws. |
cache.key | permissions.cache | — | Cache key for the catalog. A blank value is not set, so the default applies; a non-string value throws. |
cache.ttl | 300 | PERMISSIONS_CACHE_TTL | Catalog TTL in seconds, at least 1 — short on purpose, it bounds a missed invalidation. An int or a canonical integer string; blank is not set, so 300 applies; “five”, “1.5” or 0 throws InvalidConfigurationException. |
There is no guard concept — no guard_name column, config key or parameter. The package is single-guard by design.
Environment
The deployment-sensitive keys are env-backed:
# bigint | uuid | ulid — set before you publish and run the migrations
PERMISSIONS_KEY_TYPE=bigint
# Scoped and time-boxed grants — publish and run the 2.1 migrations first
PERMISSIONS_ASSIGNMENTS=false
# bigint | uuid | ulid — your scope and role-owner models; not set = PERMISSIONS_KEY_TYPE
PERMISSIONS_SCOPE_KEY_TYPE=
# false = an unscoped grant no longer counts inside a scope
PERMISSIONS_GLOBAL_APPLIES_IN_SCOPE=true
# fallback | none | any
PERMISSIONS_DESCRIPTION_FALLBACK=fallback
# "default" uses the app's default cache store
PERMISSIONS_CACHE_STORE=default
PERMISSIONS_CACHE_TTL=300Set table_names and key_type before you migrate — both are read when the migrations run, and column names are fixed. A blank table name is not set, so its default applies; a non-string table name throws InvalidConfigurationException.
Scoped and time-boxed grants
The three assignments keys are off by default and change nothing until you switch them on — scope_key_type is read by the migrations like key_type, so set it first. What they unlock is documented in Scoped & time-boxed grants and Tenant-defined roles:
# Only when your scope models key differently from your holders — before migrating
PERMISSIONS_SCOPE_KEY_TYPE=ulid
# After the 2.1 migrations ran
PERMISSIONS_ASSIGNMENTS=trueShow your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.