2

A Laravel 8 application with Sanctum.

When I send a request to a defined route using Postman with an access token the response is correct. I'm happy with this.

When I send a request to a defined route using Postman without an access token the response is 401 Access denied. I'm happy with this.

When I send a request to an undefined route using Postman with an access token the response is 401 Unauthenticated. I'm NOT happy with this. I want a more appropriate response, such as 404.

I don't know how to choose what code from my application to include this question. Please ask me for whatever might be useful and I'll add it.

Update:

Thanks to the answer by @MartinZeitler I worked out that the problem is caused by me making Nova accessible at / instead of /nova.

I did this in /config/nova.php by changing

'path' => '/nova', to 'path' => '/',.

If I revert this to '/nova' then everything works as I expect it to.

But I need Nova at /, so what can I do?

cja
  • 9,512
  • 21
  • 75
  • 129
  • 3
    Is it possible that you accidentally restricted access to your 404 page? Maybe a dumb question, but I only ask because I know a guy who actually did this, who may or may not be me – Don't Panic Aug 03 '21 at 21:19
  • @Don'tPanic I don't know how to restrict access to my 404 page. Which doesn't mean I haven't done it! – cja Aug 03 '21 at 21:20
  • This was not something I did in Laravel (okay, it was me). It was in a symfony app that restricted routes based on regular expressions, and I unintentionally restricted every route in the app. After looking at the sanctum docs, it looks like you have to explicitly protect each route, so it doesn't look like that could have happened in this case. Just a thought. – Don't Panic Aug 03 '21 at 21:30
  • 2
    checked at Laravel 8 with sanctum - undefined route with token - 404, not 401. maybe you define auth middleware in Kernel for all routes? – Maksim Aug 03 '21 at 22:09
  • 1
    @cja Please share your route `api.php` – S N Sharma Aug 13 '21 at 05:27
  • Can you review this https://stackoverflow.com/a/31621512/13875884 – Furkan ozturk Aug 13 '21 at 07:48
  • You had to make some modification in the middleware priority or Service Providers to get this behavior, because the default behavior of a Laravel + Sanctum installation should return a 404 error instead of 401. I have tested it myself a few moments ago and this is how it works by default. Maybe placing the content of `app\Http\Kernel.php` could help us. – MrEduar Aug 14 '21 at 15:41
  • @cja does my answer helped you. if not you can share your `App\Http\Kernel.php` in order to find out the problem – Abilogos Aug 18 '21 at 12:28
  • I don't have the source code of Nova but maybe the undefined route you request beings captured by Nova because you run Nova at root `/` path, you can try disable auth and send a request to that undefined route to make sure it's not captured by Nova – Chinh Nguyen Sep 30 '21 at 04:49
  • what are all the composer package you are using – ManojKiran A Sep 30 '21 at 12:30

5 Answers5

1

It's difficult to answer a routing question without, eg. the output of php artisan route:list.
The 401 likely comes from Sanctum or from missing a catch-all route Route::any('', [ ... ]).
Since Laravel 8.26.0, there is a new missing() method available.

Beside that, my best bet would be Illuminate\Foundation\Http\Kernel ...

/**
 * The priority-sorted list of middleware.
 *
 * This forces non-global middleware to always be in the given order.
 *
 * @var array
 */
protected $middlewarePriority = [];
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
0

401 & 404 are exceptions that exit the application flow from normal behavior. in your situation it seems The 401 exception get executed sooner, and doesn't let the 404 to get executed.

if these exception controls has been placed in the middlewares, you could change the execution order of middlewares from The App\Http\Kernel

for route middleware from $middlewarePriority

for global middleware from $middleware

but The url not match error (The 404) occurs here :

Symfony\Component\Routing\Matcher The method: match(), and it is out of middlewares scope.

but how to prevent the 401 from running first? this exception is thrown from the authentication middleware,

The Middlewares can get called in 3 places in the laravel:

  1. as Global Middleware
  2. as Route Parameter Middleware
  3. only get called in the Controller's Constructor

I have tested, that if The middleware is Global it gets executed, before the Url not match 404.

In the laravel docs, it is mentioned that:

The withoutMiddleware method can only remove route middleware and does not apply to global middleware.

I would translated it to:

The Global Middleware has executed before we get to the routes files

TL;DR

so I guess, You have added the authentication middleware in the $middleware. and I think you have to move it ('auth' => \App\Http\Middleware\Authenticate::class) to the $routeMiddleware array.

then use the middleware(auth:sanctum) in The routes files or the RouteServiceProvider

Abilogos
  • 4,777
  • 2
  • 19
  • 39
0

Maybe need to check a FormRequest class which handle your method in the controller, and then check method authorize he is should return when true for example

public function authorize()
{
   return auth('sanctum')->check(); // or for test just return true
}
0

try to add this to the Handler.php file in the register function in Exceptions directory.

  $this->renderable(function (NotFoundHttpException $e, $request) {
      //json response
      return $this->error('Not found', 404);

      // return 404 as html view
      // abort(404);
   });
0

You can create custom exception handling to handle all exceptions.

public function register()
{
    $this->renderable(function (\Exception $e, $request) {
        if($request->is('api/*'))
            return $this->handleException($request, $e);
    });
}

public function handleException($request, \Exception $exception)
{
    if ($exception instanceof ValidationException) {
       return $this->sendValidationError($exception->errors());
    }

    if ($exception instanceof NotFoundHttpException) {
        return $this->sendError([], 404, __('message.page_not_found'));
    }

    if ($exception instanceof AuthenticationException) {
        return $this->sendError([], 401, __('auth.unauthorized'));
    }

    if ($exception instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
        return $this->sendError([], 404, __('message.not_found'));
    }

    if($request->is('api/*')) {
       return $this->sendError([], 501, __('message.error_message'));
    }
}
swaroop suthar
  • 632
  • 3
  • 19