Skip to content

Configuration

config/access.php controls all package behavior. Below is the full config with every option shown.

Full Config File

php
<?php

use App\Enums\Permission;
use App\Enums\CompanyRole;
use App\Models\Company;

return [

    /*
    |--------------------------------------------------------------------------
    | User Model
    |--------------------------------------------------------------------------
    |
    | The authenticatable model that receives role and permission assignments.
    | Same for both scoped and global-only setups.
    |
    */

    'user_model' => 'App\\Models\\User',

    /*
    |--------------------------------------------------------------------------
    | Permission Enums
    |--------------------------------------------------------------------------
    |
    | Backed enum classes used by `access:sync` to validate permissions.
    | Same for both scoped and global-only setups.
    |
    */

    'permission_enums' => [
        Permission::class,
    ],

    /*
    |--------------------------------------------------------------------------
    | Default Scope Model
    |--------------------------------------------------------------------------
    |
    | DIFFERENCE BETWEEN MODES:
    |
    |   Scoped mode:     Set to your scope model class (e.g., Company::class)
    |   Global-only:     Leave as null
    |
    | This is used by commands like `debug:access --scope=company:1` to
    | resolve scope strings. It does NOT affect authorization logic itself.
    |
    */

    'default_scope_model' => Company::class, // Scoped mode
    // 'default_scope_model' => null,        // Global-only mode

    /*
    |--------------------------------------------------------------------------
    | Scaffolded Team Scope
    |--------------------------------------------------------------------------
    |
    | Written by `access:scope`. This records the app-owned model and naming
    | selected for generated team/company/workspace/tenant support.
    |
    */

    'teams' => [
        'model' => Company::class,
        'singular' => 'company',
        'plural' => 'companies',
    ],

    /*
    |--------------------------------------------------------------------------
    | Invitations
    |--------------------------------------------------------------------------
    |
    | Used by the invitation flow generated by `access:scope`.
    |
    */

    'invitations' => [
        'require_existing_user' => false,
        'expiry_days' => 7,
        'redirect_after_accept' => 'dashboard',
    ],

    /*
    |--------------------------------------------------------------------------
    | Cache
    |--------------------------------------------------------------------------
    |
    | Permission resolution caching. Same for both modes.
    |
    */

    'cache' => [
        'enabled' => env('APP_ENV') !== 'testing',
        'key' => 'access.permissions',
        'ttl' => null, // null = forever until cache clear
    ],

    /*
    |--------------------------------------------------------------------------
    | Scoped Roles
    |--------------------------------------------------------------------------
    |
    | DIFFERENCE BETWEEN MODES:
    |
    |   Scoped mode:     Define roles here. Each assignment is tied to a
    |                    specific scope model instance via in($model).
    |   Global-only:     Leave empty [].
    |
    | Keys are role names. Values are arrays of Permission enum cases.
    | When using `access:scope`, prefer the generated role enum values to
    | keep membership roles and access roles aligned.
    |
    */

    'roles' => [
        CompanyRole::Owner->value => [
            Permission::CompanyMembersView,
            Permission::CompanyMembersInvite,
            Permission::CompanyMembersManage,
            Permission::RolesManage,
            Permission::CompanyUpdate,
        ],
        CompanyRole::Admin->value => [
            Permission::CompanyMembersView,
            Permission::CompanyMembersInvite,
            Permission::CompanyUpdate,
        ],
        CompanyRole::Member->value => [
            Permission::CompanyMembersView,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Global Roles
    |--------------------------------------------------------------------------
    |
    | DIFFERENCE BETWEEN MODES:
    |
    |   Scoped mode:     Use for platform-level roles that apply everywhere
    |                    regardless of scope (e.g., "Platform Admin").
    |   Global-only:     Define ALL your roles here. This is your primary
    |                    role configuration.
    |
    | Keys are role names. Values are arrays of Permission enum cases.
    |
    */

    'global_roles' => [
        'Platform Admin' => [
            Permission::SystemManage,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Gate Before Override
    |--------------------------------------------------------------------------
    |
    | When enabled, users with the specified global role bypass ALL Laravel
    | Gate and Policy checks. Same for both modes.
    |
    | Use with caution — this grants unrestricted access.
    |
    */

    'gate_before' => [
        'enabled' => false,
        'global_role' => 'Platform Admin',
    ],

];

Options Reference

user_model : The authenticatable model that receives assignments. Same for both modes.

permission_enums : Backed enum classes used by access:sync. Same for both modes. access:install --enum creates App\Enums\Permission and writes it here. access:scope --name=company adds starter company permission cases to App\Enums\Permission when that file exists. Add more enum classes to this array only when you intentionally want modular permission enums.

default_scope_model : Scoped: set to your scope model class (e.g., Company::class). Global-only: leave as null. Used by dev commands to resolve scope strings like company:1. This is a model class, not a table name; the model determines its own table.

teams : Metadata for the app-owned scope generated by access:scope. The key remains teams for compatibility even when the domain term is company, workspace, tenant, or another name.

invitations : Settings for the invite flow generated by access:scope. require_existing_user controls whether brand-new users can register from an invitation, expiry_days controls default invitation lifetime, and redirect_after_accept is the named route used after a successful join.

roles : Scoped: define your per-scope roles here. Global-only: leave empty []. If access:scope generated a role enum, use enum values as keys, such as CompanyRole::Admin->value, instead of repeating raw strings.

global_roles : Scoped: optional platform-level roles that apply everywhere. Global-only: define all your roles here.

The distinction matters when seeding. roles are assigned with $user->in($scope)->assignRole(...); global_roles are assigned with $user->assignGlobalRole(...). See Seed roles and permissions for first-time and update workflows.

cache : Permission resolution caching. Same for both modes.

gate_before : Optional Laravel Gate override for a global role. Same for both modes.

Scoped Mode Quick Reference

php
'default_scope_model' => Company::class,

'roles' => [
    CompanyRole::Owner->value => [Permission::CompanyMembersView, Permission::CompanyMembersInvite],
],

'global_roles' => [
    'Platform Admin' => [Permission::SystemManage],
],
php
$user->in($company)->assignRole(CompanyRole::Owner);
$user->in($company)->can(Permission::CompanyMembersInvite);

Global-Only Mode Quick Reference

php
'default_scope_model' => null,

'roles' => [],

'global_roles' => [
    'Admin' => [Permission::UsersView, Permission::UsersInvite],
    'Viewer' => [Permission::UsersView],
],
php
$user->assignGlobalRole('Admin');
$user->canGlobally(Permission::UsersInvite);

Gate Before Override

When enabled, the configured global role can bypass Laravel Gate checks:

php
'gate_before' => [
    'enabled' => false, 
    'enabled' => true, 
    'global_role' => 'Platform Admin',
],

Use this only when platform administrators should be allowed through every Laravel policy and gate check.