Hey there
I'm using laravel passport to setup authentication from front end project to an api. It used to work without any problems, but from time to time the api prompted me a basic authentication alert instead of the laravel login page.
This happens when I'm logged in on the api, but not through the front end, so when I go to the front end login page which redirects me to the api login, it just shows me the basic auth prompt...
Now since a few days, it sometimes shows me the laravel login page, but after I submit (login) it stays on the same page and shows me a basic authentication alert.
when it does work, it always keeps asking me to autorize the client, also when i've done this previously...
Anyone know what might cause this and how to fix it?
(putting in the same correct credentials in the prompt also fails...)
Hi, @jorenvh1. I also have this problem (Use implicit flow to authorize api requests). After few hours of research I found the problem (it's ridiculous and should be documentated or updated to be more clear for users).
Here \Laravel\Passport\Http\Controllers\AuthorizationController::authorize You can find call to:
$this->server->validateAuthorizationRequest($psrRequest);. In my case of implicit flow next call will be:
\League\OAuth2\Server\Grant\ImplicitGrant::validateAuthorizationRequest. In case of redirect url passed in url not match redirect url in client (specified by client_id) will be thrown
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient();
And after that, in Passport exceptions handler:
\Laravel\Passport\Http\Controllers\HandlesOAuthErrors::withErrorHandling
will be executed block:
catch (OAuthServerException $e) {
$this->exceptionHandler()->report($e);
return $e->generateHttpResponse(new Psr7Response);
}
That response add http-auth headers which cause problem.
$headers = [
'Content-type' => 'application/json',
];
// Add "WWW-Authenticate" header
//
// RFC 6749, section 5.2.:
// "If the client attempted to authenticate via the 'Authorization'
// request header field, the authorization server MUST
// respond with an HTTP 401 (Unauthorized) status code and
// include the "WWW-Authenticate" response header field
// matching the authentication scheme used by the client.
// @codeCoverageIgnoreStart
if ($this->errorType === 'invalid_client') {
$authScheme = 'Basic';
if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false
&& strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0
) {
$authScheme = 'Bearer';
}
$headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
}
So, You cant authorize with this basic auth, coz it's kind of response to Exception thrown during authorization. Cucumbersome stuff.
In my case: I just fix redirect uri value, but it was hard ((
Hope it wil be helpfull for You. gl lf ))
Ok. Few additional hours and I found solution. But I'm not sure this is completely valid.
<?php
namespace App\Http\Middleware;
class HandleInvalidClientException
{
/**
* @param \Illuminate\Http\Request $request
* @param $next
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle($request, $next)
{
$response = $next($request);
/** @var \Symfony\Component\HttpFoundation\Response $response */
if ($response->getStatusCode() == 401 && $request->is('*oauth/authorize*')) {
$data = json_decode($response->getContent(), true);
if (array_get($data, 'error') === 'invalid_client' && $response->headers->has('WWW-Authenticate')) {
$response->headers->remove('WWW-Authenticate');
}
}
return $response;
}
}
Just add this middleware class to Your web group of routes middleware.
!ping @taylorotwell @jorenvh1.
Plz help us )))
I'm newbe in OAuth and Passport, but this WWW-Auth looks strange and it's apears in any cases of missconfiguration: wrond client id, secret, redirect uri...
Also it's will be written to Your logs as Exception, so spam to /oauth/authorize with invalid credentials will write garbage into your logs or any type of errors handling.
@evgeniy-n Thanks for the quick response and help. I'll take a look at your solution ASAP.
Just hit the same issue on a new Laravel install.
Editing the the redirect url in the oauth_clients table to match the exact url I use in the client did the trick.
I still expect Passport to behave differently. Shouldn't this return a 400 error saying the url we provided is invalid ?
EDIT: From the comments I thought the file at fault was in Passport, but it's actually a League file https://github.com/thephpleague/oauth2-server/blob/master/src/Exception/OAuthServerException.php @ getHttpHeaders
Looks like it was decided to return these headers for every invalid_client errors instead of strictly detecting the case covered by that RFC rule... Still a bad experience in Passport to inherit that.
removing redirect_uri from the query string solved this problem for me. After authorization passport sent me to the saved redirect uri for the client.
I found the solution was to make sure the redirect uri registered with the client id and the one in the api request are exactly the same.
I'm getting this even though the redirect_uris are identical - as they should be; that's one of the key validations that the OAuth server needs to provide.
Most helpful comment
Hi, @jorenvh1. I also have this problem (Use implicit flow to authorize api requests). After few hours of research I found the problem (it's ridiculous and should be documentated or updated to be more clear for users).
Here
\Laravel\Passport\Http\Controllers\AuthorizationController::authorizeYou can find call to:$this->server->validateAuthorizationRequest($psrRequest);. In my case of implicit flow next call will be:\League\OAuth2\Server\Grant\ImplicitGrant::validateAuthorizationRequest. In case of redirect url passed in url not match redirect url in client (specified by client_id) will be thrownAnd after that, in Passport exceptions handler:
\Laravel\Passport\Http\Controllers\HandlesOAuthErrors::withErrorHandlingwill be executed block:
That response add http-auth headers which cause problem.
So, You cant authorize with this basic auth, coz it's kind of response to Exception thrown during authorization. Cucumbersome stuff.
In my case: I just fix redirect uri value, but it was hard ((
Hope it wil be helpfull for You. gl lf ))