
Implementing Row-Level Security in Filament Tables with applyRowAccessPolicy
- Published: 07 May 2025 Updated: 07 May 2025
Learn how to implement row-level security in Filament tables using the applyRowAccessPolicy macro that filters query results based on user permissions through Laravel's policy system.

Understanding the applyRowAccessPolicy Macro
The applyRowAccessPolicy
macro provides an elegant solution for implementing row-level security in Filament tables. This macro integrates with Laravel's policy system to filter table data based on user permissions.
1Table::macro('applyViewRowScope', function (\Closure | bool $condition = true): Table {
2 if ($condition instanceof \Closure) {
3 $condition = $this->evaluate($condition);
4 }
5
6 /**
7 * Store the view row scope condition in Laravel's service container.
8 *
9 * How this works:
10 * 1. We generate a unique ID for each Table instance using spl_object_hash()
11 * 2. We create a container binding with a key specific to this Table instance
12 * 3. The condition value (true/false) is stored in the container
13 *
14 * The container binding will be automatically cleaned up when the Table instance
15 * is garbage collected, as the binding key is unique to this instance.
16 */
17 $tableId = spl_object_hash($this);
18 app()->instance('filament.table.viewRowScope.' . $tableId, $condition);
19
20 return $this->modifyQueryUsing(function (\Illuminate\Database\Eloquent\Builder $query) use ($tableId): \Illuminate\Database\Eloquent\Builder {
21 // Check the container for this Table's specific viewRowScope setting
22 // Defaults to true if no binding exists (fallback for safety)
23 $shouldApply = app()->bound('filament.table.viewRowScope.' . $tableId)
24 ? app()->make('filament.table.viewRowScope.' . $tableId)
25 : true;
26
27 if (! $shouldApply) {
28 return $query;
29 }
30
31 $model = $query->getModel();
32
33 if (! $model) {
34 return $query;
35 }
36
37 $policy = \Gate::getPolicyFor($model);
38
39 if (! $policy || ! method_exists($policy, 'viewRow')) {
40 return $query;
41 }
42
43 $modifiedQuery = $policy->viewRow(user(), $query);
44
45 if (! $modifiedQuery instanceof \Illuminate\Database\Eloquent\Builder) {
46 throw new \RuntimeException("The viewRow method for " . $policy::class . " must return an instance of Illuminate\Database\Eloquent\Builder.");
47 }
48
49 return $modifiedQuery;
50 });
51 });
When applied to a table, this macro modifies the underlying query by checking for an applyRowAccessPolicy
method in your model's Policy class. It then uses this method to filter records the current user is allowed to view.
How It Works
The macro accepts an optional condition parameter that determines whether the policy should be applied
It stores this condition in Laravel's service container with a unique identifier for each table instance
It modifies the query by checking if a policy exists for the model and if it contains an
applyRowAccessPolicy
methodIf found, it calls this method, passing the current user and the query builder
The policy method returns a modified query with appropriate row-level filters applied
Implementation Example
Define the method in your model's Policy:
1// PostPolicy.php
2public function applyRowAccessPolicy(User $user, Builder $query): Builder
3{
4 // Users can only see their own posts unless they're admins
5 return $user->isAdmin() ? $query : $query->where('user_id', $user->id);
6}
Apply the macro to your Filament table:
1// PostResource
2public static function table(Table $table): Table
3{
4 return $table
5 ->applyRowAccessPolicy()
6 ->columns([
7 // your columns here
8 ]);
9}
This simple implementation ensures users only see rows they're authorized to access, providing robust, reusable row-level security across your Filament application.

Related Tricks:
make all Field or any components translatable
Learn how to implement row-level security in Filament tables using the applyRowAccessPolicy macro that filters query results based on user permissions through Laravel's policy system.
how to use a resource with multiple models