Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jeroenvip's avatar

Return a view instead of the default THIS ACTION IS UNAUTHORIZED with Laravel Policies

Hello, I am new to Laravel and working on permissions. This is working.

<?php

namespace App\Policies;

use App\Models\User;

class UserPolicy
{
    public function isAdmin(User $user): bool
    {
        return $user->usermeta()->where('meta_key', 'role')->first()->meta_value === 'admin';
    }
}

How can I return a view instead of the default 403 THIS ACTION IS UNAUTHORIZED

0 likes
9 replies
LaryAI's avatar
Level 58

To return a custom view instead of the default "THIS ACTION IS UNAUTHORIZED" message when a policy check fails in Laravel, you can handle the AuthorizationException in your exception handler. Here's how you can do it:

  1. Open the app/Exceptions/Handler.php file.

  2. In the render method, check for the AuthorizationException and return a custom view.

Here's an example of how you can implement this:

use Illuminate\Auth\Access\AuthorizationException;

public function render($request, Throwable $exception)
{
    if ($exception instanceof AuthorizationException) {
        // Return a custom view for unauthorized access
        return response()->view('errors.custom-unauthorized', [], 403);
    }

    return parent::render($request, $exception);
}
  1. Create a new view file for your custom unauthorized page, for example, resources/views/errors/custom-unauthorized.blade.php.

  2. In the custom-unauthorized.blade.php file, you can design your custom error message:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Unauthorized</title>
</head>
<body>
    <h1>Unauthorized Access</h1>
    <p>You do not have permission to view this page.</p>
</body>
</html>

With this setup, whenever an authorization check fails, Laravel will render your custom view instead of the default 403 error page.

jeroenvip's avatar

Already found a working solution

    public function index(User $user, Request $request)
    {
        if (!auth()->check() || !auth()->user()->can('isAdmin', $user)) {
            return redirect('/auth/login');
        }

        // Get the data
        $search = filter_var($request->search, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        $users = User::with('wallet', 'usermeta')
            ->where('email', 'like', "%$search%")
            ->orWhereHas('usermeta', function ($query) use ($search) {
                $query->where('meta_value', 'like', "%{$search}%");
            })
            ->simplePaginate(15);
        return view('admin.users.index', ['users' => $users, 'user' => auth()->user()]);
    }

1 like
Shivamyadav's avatar

@jeroenvip I think it will be better to use role middleware and provide the role on the particular route url on which you want to use ..

Everytime you have to write the same code which is unnecessary takes lines of codes and duplications and looks messy

1 like
jeroenvip's avatar

@shivamyadav You got a point.

For me, the routes file is an index of the biggest book you can find. It needs to be clear, uncluttered, and readable without thinking. No grouping, resource usage, or middleware. Just single route lines only telling what routes are available in the project.

Authorization, validation, CRUD are all events that should be placed in a controller. I mean, that's what a controller is supposed to do, right, control things ?

Sometimes repeating yourself results in better readability.

At least my 2 cents.

2 likes
vincent15000's avatar

@jeroenvip You should be able to do that without modifying your code in the controller. See my answer below.

Furthermore, auth()->user()->can('isAdmin', $user) is strange ... a user can isAdmin ? Did you mean auth()->user()->isAdmin() ?.

jeroenvip's avatar

@vincent15000

I have created a UserPolicy using the policy discovery https://laravel.com/docs/12.x/authorization#registering-policies

"In addition, the policy name must match the model name and have a Policy suffix. So, a User model would correspond to a UserPolicy policy class."

Which creates a simple rule based authentication. If there are other better "best practices" I am all ear.

vincent15000's avatar

Unauthorized is a 403 error.

The easiest way is to create the view 403.blade.php inside an views/errors folder.

If there is a 403 error, the 403.blade.php view will automatically called.

You can also add a custom view via the Exception handler.

jeroenvip's avatar

@vincent15000

The easiest way is to create the view 403.blade.php inside a views/errors folder. Works like a charm.

Stupid question. Does this work for every http status code ? Example 404.blade.php would also work ?

1 like
vincent15000's avatar

@jeroenvip Yes it works with error code.

So you can create a 404.blade.php or a 500.blade.php file for example.

Please or to participate in this conversation.