I am using Laravel API authentication with a token. (as explained here: https://laravel.com/docs/5.8/api-authentication#protecting-routes)
I am running some tests with Postman and it works fine. When I try to access the route without a valid token, I see that the response is the (html of the) login page of my app. How can I return a Unauthorized
message instead of the complete login page? Do I have to create a custom middleware?
Controller
class ExampleController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
public function show(Request $request) {
return response()->json($request->user()->name);
}
}
Please add the method in the class Handler in the file location app/Exceptions/Handler.php
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest(route('login'));
}
And also add the following line above the class in the same file as mentioned above: use Illuminate\Auth\AuthenticationException;
In the postman within the headers section please add the following header : X-Requested-With:XMLHttpRequest
Hope this helps and resolves the issue. Thanks.
I am using Laravel 8 with passport.
In my case I had to add an "unauthenticated" function inside app/Http/Middleware/Authenticate
like so:
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
// Add new method
protected function unauthenticated($request, array $guards)
{
abort(response()->json(
[
'api_status' => '401',
'message' => 'UnAuthenticated',
], 401));
}
}
Be sure to be sending the right headers in your request
Content-Type: application/json
Laravel 8 update:
default handler already handle this scenario
File: \Illuminate\Foundation\Exceptions\Handler.php
/**
* Convert an authentication exception into a response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest($exception->redirectTo() ?? route('login'));
}
This is how Laravel do expectsJson
in \Illuminate\Http\Concerns\InteractsWithContentTypes.php
/**
* Determine if the current request probably expects a JSON response.
*
* @return bool
*/
public function expectsJson()
{
return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson();
}
/**
* Determine if the current request is asking for JSON.
*
* @return bool
*/
public function wantsJson()
{
$acceptable = $this->getAcceptableContentTypes();
return isset($acceptable[0]) && Str::contains($acceptable[0], ['/json', '+json']);
}
So note that content type header of request is useless. The header useful is "Accept: application/json"
Make sure you are sending correct headers
Accept application/json
Also, you can create your own Middleware for this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With