JRCSalter's avatar

Redirect RouteNotFound error page to custom 403 error

I specify my routes like this

Route::get('/collection', [CollectionController::class, 'index'])->middleware('auth');

However, if I navigate to localhost/collection without being logged in, I get a Laravel error page with a RouteNotFoundException. This is useful for debugging, but I don't want it to appear in production code. Ideally, I'd like to display a 403 error instead. How do I acheive this?

I've attempted to wrap it in try/catchblock,but this doesn't catch the exception. Presumably because it is being handled by Laravel. ChatGPT suggested I put the following in my App\Exceptions\Handler class:

public function render($request, Throwable $exception)
{
    if ($exception instanceof AuthorizationException) {
        // Customize the response for AuthorizationException (403 Forbidden)
        return response()->view('errors.403', [], 403);
    }

    return parent::render($request, $exception);
}

But this also didn't work. Surely there must be an easy way around this, as I'm sure it's a common thing to want to do.

I can also set APP_DEBUG=false in my .env file. This gets rid of the error message, but returns a 500 error, which is not the correct response code.

Edit:

I seem to have solved this.

Previously, my Authenticate middleware class looked like this:

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     */
    protected function redirectTo(Request $request): ?string
    {
        return $request->expectsJson() ? null : route('login');
    }
}

The problem seemed to be related to the return statement in redirectTo. I changed the line to the following:

return $request->expectsJson() ? null : 'login';

And this redirected the user to the login page. Not a 403 error, but at least I can handle the situation.

0 likes
8 replies
arthvrian's avatar

Did you try this?

APP_DEBUG=false

in your .env file

arthvrian's avatar

route exists?

php artisan route:list

Controller exists and it is well imported? method exists?

with everything right should show the 403 error page or redirect to login page NOT the 500 error page

JRCSalter's avatar

@arthvrian I ran that command, and among other things, I got this:

GET|HEAD collection ........................... CollectionController@index

So I can see no problem there. The route works when logged in. I just don't want the user to see the Laravel error page if they navigate to this page while not logged in.

arthvrian's avatar

@JRCSalter as @snapey said, the login route appears in route:list? if it does and it is custom, controller and method exist?

what happens when you go to localhost/login in your browser?

JRCSalter's avatar

@arthvrian localhost/login works fine. I've since found a solution which works, and I've updated my question with it. Though I'm not certain why it works.

Snapey's avatar

@JRCSalter It works because you have a /login route, but you don't have a name('login') on that route.

The middleware is trying to find a route named login and when it can't find it, a 500 error occurs.

Standard practice is that a user trying to reach that collection page, and is not logged in should be redirected to the login page and then when they have logged in they are redirected to the page they "intended" to reach (the collections page)

All you have done in your fix is to change a named route for an actual route.

Snapey's avatar

check your auth middleware to see where it is redirecting to when the user is not logged in. I assume you have deleted or moved the login route?

Please or to participate in this conversation.