New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

After I press login, browser prompts me with basic authentication alert #340

Closed
jorenvh1 opened this Issue Apr 7, 2017 · 7 comments

Comments

Projects
None yet
6 participants
@jorenvh1

jorenvh1 commented Apr 7, 2017

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...)

@evgeniy-n

This comment has been minimized.

Show comment
Hide comment
@evgeniy-n

evgeniy-n Apr 8, 2017

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 ))

evgeniy-n commented Apr 8, 2017

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 ))

@evgeniy-n

This comment has been minimized.

Show comment
Hide comment
@evgeniy-n

evgeniy-n Apr 8, 2017

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 commented Apr 8, 2017

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.

@jorenvh1

This comment has been minimized.

Show comment
Hide comment
@jorenvh1

jorenvh1 Apr 10, 2017

@evgeniy-n Thanks for the quick response and help. I'll take a look at your solution ASAP.

jorenvh1 commented Apr 10, 2017

@evgeniy-n Thanks for the quick response and help. I'll take a look at your solution ASAP.

@jorenvh1 jorenvh1 closed this Apr 13, 2017

@clarkwinkelmann

This comment has been minimized.

Show comment
Hide comment
@clarkwinkelmann

clarkwinkelmann Jun 20, 2017

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.

clarkwinkelmann commented Jun 20, 2017

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.

@prionkor

This comment has been minimized.

Show comment
Hide comment
@prionkor

prionkor Jul 16, 2017

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.

prionkor commented Jul 16, 2017

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.

@guezandy

This comment has been minimized.

Show comment
Hide comment
@guezandy

guezandy Jul 30, 2017

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.

guezandy commented Jul 30, 2017

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.

@simonhamp

This comment has been minimized.

Show comment
Hide comment
@simonhamp

simonhamp Sep 8, 2017

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.

simonhamp commented Sep 8, 2017

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment