Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return unauthorized using Laravel API Authentication

Tags:

laravel

api

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);
    }
 }
like image 695
user3253002 Avatar asked May 01 '19 18:05

user3253002


5 Answers

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.

like image 63
Saibal Roy Avatar answered Oct 20 '22 07:10

Saibal Roy


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));
    }
}
like image 31
The Blind Hawk Avatar answered Oct 20 '22 07:10

The Blind Hawk


Be sure to be sending the right headers in your request

Content-Type: application/json
like image 33
Jose Palazuelos Avatar answered Oct 20 '22 06:10

Jose Palazuelos


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"

like image 45
realtebo Avatar answered Oct 20 '22 08:10

realtebo


Make sure you are sending correct headers

Accept        application/json

Also, you can create your own Middleware for this.

like image 23
Tariq Avatar answered Oct 20 '22 08:10

Tariq