Skip to main content
Laravel Permission provides custom Blade directives that make it easy to show or hide content based on user permissions and roles. These directives are cleaner and more readable than using @if statements with method calls.

Permission Directives

Check user permissions directly in your Blade templates.

@haspermission

Show content only if the user has a specific permission:
@haspermission('edit articles')
    <a href="{{ route('articles.edit', $article) }}" class="btn btn-primary">
        Edit Article
    </a>
@endhaspermission
@haspermission('delete articles')
    <form action="{{ route('articles.destroy', $article) }}" method="POST">
        @csrf
        @method('DELETE')
        <button type="submit" class="btn btn-danger">Delete</button>
    </form>
@endhaspermission
Behind the scenes: The @haspermission directive calls auth()->user()->checkPermissionTo($permission), which returns false gracefully if the permission doesn’t exist.

Role Directives

Show or hide content based on user roles.

@role

Show content only if the user has a specific role:
@role('admin')
    <a href="{{ route('admin.dashboard') }}" class="nav-link">
        Admin Dashboard
    </a>
@endrole
@role('writer')
    <div class="alert alert-info">
        Welcome, Writer! You can create and edit articles.
    </div>
@endrole

@hasrole

Alias to @role - works identically:
@hasrole('editor')
    <a href="{{ route('articles.pending') }}">
        Pending Articles ({{ $pendingCount }})
    </a>
@endhasrole
@hasrole and @role are functionally identical. Use whichever reads better in your templates.

@hasanyrole

Show content if user has any of the specified roles:
@hasanyrole('writer|editor|admin')
    <div class="content-management-panel">
        <h3>Content Management</h3>
        <!-- Content management tools -->
    </div>
@endhasanyrole
@hasanyrole('writer|editor')
    <a href="{{ route('articles.create') }}">Create Article</a>
@endhasanyrole

@hasallroles

Show content only if user has all specified roles:
@hasallroles('writer|reviewer')
    <div class="alert alert-success">
        You can write and review articles!
    </div>
@endhasallroles
User must have ALL roles listed. If they’re missing even one, the content won’t show.

@hasexactroles

Show content only if user has exactly these roles (no more, no less):
@hasexactroles('writer|editor')
    <p>You have exactly the Writer and Editor roles.</p>
@endhasexactroles
This directive checks that the user has precisely these roles and no others.

Using Laravel’s Native @can Directive

Laravel Permission integrates with Laravel’s built-in authorization, so @can works seamlessly:
@can('edit articles')
    <a href="{{ route('articles.edit', $article) }}">Edit</a>
@endcan

@can('delete articles')
    <button type="submit" class="btn btn-danger">Delete</button>
@endcan
@can('edit articles')
    <a href="{{ route('articles.edit', $article) }}">Edit</a>
@elsecan('view articles')
    <a href="{{ route('articles.show', $article) }}">View</a>
@else
    <span class="text-muted">No access</span>
@endcan

Practical Examples

<nav class="navbar">
    <ul class="nav">
        <li><a href="{{ route('home') }}">Home</a></li>
        
        @role('writer|editor|admin')
            <li><a href="{{ route('articles.index') }}">Articles</a></li>
        @endrole
        
        @can('create articles')
            <li><a href="{{ route('articles.create') }}">New Article</a></li>
        @endcan
        
        @role('admin')
            <li><a href="{{ route('admin.users') }}">Users</a></li>
            <li><a href="{{ route('admin.roles') }}">Roles</a></li>
        @endrole
    </ul>
</nav>

Article Action Buttons

<div class="article-actions">
    @can('view articles')
        <a href="{{ route('articles.show', $article) }}" class="btn btn-info">
            View
        </a>
    @endcan
    
    @can('edit articles')
        <a href="{{ route('articles.edit', $article) }}" class="btn btn-primary">
            Edit
        </a>
    @endcan
    
    @can('delete articles')
        <form action="{{ route('articles.destroy', $article) }}" method="POST" class="d-inline">
            @csrf
            @method('DELETE')
            <button type="submit" class="btn btn-danger"
                    onclick="return confirm('Are you sure?')">
                Delete
            </button>
        </form>
    @endcan
    
    @role('admin')
        <a href="{{ route('articles.audit', $article) }}" class="btn btn-secondary">
            Audit Log
        </a>
    @endrole
</div>

User Dashboard

<div class="dashboard">
    <h1>Dashboard</h1>
    
    @hasanyrole('writer|editor')
        <div class="card">
            <h3>Your Articles</h3>
            <p>You have {{ $articleCount }} articles</p>
            <a href="{{ route('articles.mine') }}">View My Articles</a>
        </div>
    @endhasanyrole
    
    @role('editor')
        <div class="card">
            <h3>Pending Review</h3>
            <p>{{ $pendingCount }} articles awaiting review</p>
            <a href="{{ route('articles.pending') }}">Review Articles</a>
        </div>
    @endrole
    
    @role('admin')
        <div class="card">
            <h3>System Stats</h3>
            <ul>
                <li>Total Users: {{ $userCount }}</li>
                <li>Total Articles: {{ $totalArticles }}</li>
                <li>Active Sessions: {{ $activeSessions }}</li>
            </ul>
        </div>
    @endrole
</div>

Admin Settings

<div class="settings">
    <h2>Settings</h2>
    
    @haspermission('edit settings')
        <form action="{{ route('settings.update') }}" method="POST">
            @csrf
            <!-- Settings form -->
            <button type="submit" class="btn btn-primary">Save Settings</button>
        </form>
    @elsehaspermission
        <div class="alert alert-info">
            Settings are view-only. Contact an administrator to make changes.
        </div>
        <!-- Read-only settings display -->
    @endhaspermission
</div>

How Directives Work

The directives are registered in the PermissionServiceProvider:
// From: src/PermissionServiceProvider.php:68-82

protected function registerBladeExtensions(BladeCompiler $bladeCompiler): void
{
    $bladeMethodWrapper = '\\Spatie\\Permission\\PermissionServiceProvider::bladeMethodWrapper';

    // Permission checks
    $bladeCompiler->if('haspermission', 
        fn () => $bladeMethodWrapper('checkPermissionTo', ...func_get_args())
    );

    // Role checks
    $bladeCompiler->if('role', 
        fn () => $bladeMethodWrapper('hasRole', ...func_get_args())
    );
    $bladeCompiler->if('hasrole', 
        fn () => $bladeMethodWrapper('hasRole', ...func_get_args())
    );
    $bladeCompiler->if('hasanyrole', 
        fn () => $bladeMethodWrapper('hasAnyRole', ...func_get_args())
    );
    $bladeCompiler->if('hasallroles', 
        fn () => $bladeMethodWrapper('hasAllRoles', ...func_get_args())
    );
    $bladeCompiler->if('hasexactroles', 
        fn () => $bladeMethodWrapper('hasExactRoles', ...func_get_args())
    );
}
The bladeMethodWrapper helper:
// From: src/PermissionServiceProvider.php:63-66

public static function bladeMethodWrapper(string $method, mixed $role, ?string $guard = null): bool
{
    return auth($guard)->check() && auth($guard)->user()->{$method}($role);
}
All directives automatically check if the user is authenticated. If there’s no authenticated user, they return false.

Best Practices

Use @can for permissions: Prefer @can over @haspermission as it’s Laravel’s standard and works with policies too.
<!-- Preferred -->
@can('edit articles')
    <button>Edit</button>
@endcan

<!-- Also works -->
@haspermission('edit articles')
    <button>Edit</button>
@endhaspermission
Combine with policies: Use directives for simple checks, policies for complex logic:
{{-- Simple permission check --}}
@can('edit articles')
    <button>Edit Any Article</button>
@endcan

{{-- Complex check using policy --}}
@can('update', $article)
    <button>Edit This Article</button>
@endcan
Don’t rely solely on Blade directives for security. Always validate permissions on the backend. Blade directives only control what’s displayed, not what users can access.

Next Steps

Using Middleware

Protect routes with permission middleware

Multiple Guards

Use permissions with different authentication guards

Build docs developers (and LLMs) love