ahmedsaber111
ahmedsaber111

Reputation: 822

Laravel passport API return Exception as HTML instead of JSON response

My API has been built with Laravel 5.4 Passport, authorisation and issuing access tokens is working properly, but when dealing with a resource like below using Insomnia or Postman:

Authorization: Bearer [encrypted access token goes here which has only "manage-users" scope]
Content-Type: application/json
Accept: application/json

I send above request to this url:

http://apiendpoint.loc/api/users

which has been restricted access to this recourse to tokens which has this scopes

manage-users, test-scope-1

Route::get('/users', [
    'as' => 'users', 
    'uses' => 'UsersController@index'
])->middleware(['auth:api', 'scopes:manage-users,test-scope-1']);

scopes have been defined in the:

AuthServiceProvider

Passport::tokensCan([
    'manage-users' => 'testing',
    'test-scope-1' => 'test scope',
    'test-scope-2' => 'another test scope',
]);
protected $routeMiddleware = [
    ...,
    ...,
    ...,
    'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
    'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class        
];

The token used to authorize this request has "manage-users" scope only, so I expected to get json response with unauthorized access 401 in addition to the required scope to access this resource which is "test-scope-1".

although I got a HttpException "Invalid scope(s) provided." as HTML response not json

Edit Auth-Scaffolding is not installed.

Upvotes: 1

Views: 3042

Answers (1)

ahmedsaber111
ahmedsaber111

Reputation: 822

After a lot of digging, I found a way to to work around the issue earlier in the exception handler like below:

public function render($request, Exception $exception)
{

    // If the request wants JSON (AJAX doesn't always want JSON)
    if ($request->wantsJson()) {

    if($exception instanceof MissingScopeException){
        // Define the response
        $response = [
            'errors' => 'Sorry, something went wrong.'
        ];

        // If the app is in debug mode
        if (config('app.debug')) {
            // Add the exception class name, message and stack trace to response
            //$response['exception'] = get_class($exception); // Reflection might be better here
            $response['message'] = $exception->getMessage();
            //$response['trace'] = $exception->getTrace();
        }

        // Default response of 401
        $status = 403;//forbidden

        // If this exception is an instance of HttpException
        if ($this->isHttpException($exception)) {
            // Grab the HTTP status code from the Exception
            $status = $exception->getStatusCode();
        }

        // Return a JSON response with the response array and status code
        return response()->json($response, $status);
    }

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

so I'll be able to catch the error early and return a json object as a response.

Upvotes: 0

Related Questions