stevenmaguire / oauth2-keycloak

Keycloak Provider for OAuth 2.0 Client
MIT License
203 stars 151 forks source link

Failed to parse JSON response #66

Open dvladimirov77 opened 1 year ago

dvladimirov77 commented 1 year ago

Hello.

When executing: $provider->getResourceOwner($token);

I got this error: Failed to parse JSON response: Syntax error /vendor/league/oauth2-client/src/Provider/AbstractProvider.php on line 645

Checked the token on jwt.io - it's ok

How to fix it?

firebase/php-jwt (v6.4.0) guzzlehttp/guzzle (7.5.0) guzzlehttp/promises (1.5.2) guzzlehttp/psr7 (2.4.4) league/oauth2-client (2.6.1) paragonie/random_compat (v9.99.100) psr/http-client (1.0.1) psr/http-factory (1.0.1) psr/http-message (1.0.1) ralouphie/getallheaders (3.0.3) stevenmaguire/oauth2-keycloak (4.0.0) symfony/deprecation-contracts (v2.5.2)

ReinanHS commented 1 year ago

I am also facing the same problem Failed to parse JSON response: Syntax error.

Repro steps

The example below is of the code I am running and getting error:

<?php

declare(strict_types=1);

namespace Application\Controller;

use Exception;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Stevenmaguire\OAuth2\Client\Provider\Keycloak;

class AuthCallbackController
{
    /**
     * @param Keycloak $provider
     */
    public function __construct(private Keycloak $provider)
    {
    }

    /**
     * @param Request $request
     * @param Response $response
     * @return Response
     */
    public function __invoke(Request $request, Response $response): Response
    {
        $params = $request->getQueryParams();

        $token = $this->provider->getAccessToken('authorization_code', ['code' => $params['code']]);
        $user_data = $this->provider->getResourceOwner($token);

        return $response->withStatus(200)
            ->withHeader('Content-Type', 'application/json');
    }
}

Screenshots

image

Environment settings

See the output of the composer show -i command:

fig/http-message-util         1.1.5     Utility classes and constants for use with PSR-7 (psr/http-message)
firebase/php-jwt              v6.4.0    A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.
guzzlehttp/guzzle             7.5.0     Guzzle is a PHP HTTP client library
guzzlehttp/promises           1.5.2     Guzzle promises library
guzzlehttp/psr7               2.4.4     PSR-7 message implementation that also provides common utility methods
laravel/serializable-closure  v1.3.0    Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.
league/oauth2-client          2.6.1     OAuth 2.0 Client Library
nikic/fast-route              v1.3.0    Fast request router for PHP
paragonie/random_compat       v9.99.100 PHP 5.x polyfill for random_bytes() and random_int() from PHP 7
php-di/invoker                2.3.3     Generic and extensible callable invoker
php-di/php-di                 7.0.2     The dependency injection container for humans
php-di/slim-bridge            3.3.0     PHP-DI integration in Slim
psr/container                 2.0.2     Common Container Interface (PHP FIG PSR-11)
psr/http-client               1.0.2     Common interface for HTTP clients
psr/http-factory              1.0.2     Common interfaces for PSR-7 HTTP message factories
psr/http-message              1.1       Common interface for HTTP messages
psr/http-server-handler       1.0.2     Common interface for HTTP server-side request handler
psr/http-server-middleware    1.0.2     Common interface for HTTP server-side middleware
psr/log                       3.0.0     Common interface for logging libraries
ralouphie/getallheaders       3.0.3     A polyfill for getallheaders.
slim/http                     1.3       Slim PSR-7 Object Decorators
slim/psr7                     1.6       Strict PSR-7 implementation
slim/slim                     4.11.0    Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs
stevenmaguire/oauth2-keycloak 4.0.0     Keycloak OAuth 2.0 Client Provider for The PHP League OAuth2-Client
symfony/deprecation-contracts v3.2.1    A generic function and convention to trigger deprecation notices
symfony/polyfill-php80        v1.27.0   Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
redor303 commented 1 year ago

Yeah I'm facing the same issue too. I poked around a little and found that in fact, the 'openid' scope is needed for the userinfo. There is a switch "if ($this->validateGteVersion('20.0.0')) {" in Line 210 of Keycloak.php but that does not seem to work anymore. If the condition is true, the 'openid' scope is added to the default scopes.

If I add the 'openid' scope in the default scopes above by hand Line 208 of Keycloak.php, everything works fine

ReinanHS commented 1 year ago

Yeah I'm facing the same issue too. I poked around a little and found that in fact, the 'openid' scope is needed for the userinfo. There is a switch "if ($this->validateGteVersion('20.0.0')) {" in Line 210 of Keycloak.php but that does not seem to work anymore. If the condition is true, the 'openid' scope is added to the default scopes.

If I add the 'openid' scope in the default scopes above by hand Line 208 of Keycloak.php, everything works fine

@redor303 i deeply appreciate your feedback, as it helped me solve my problem. According to the official library documentation on Github, the version parameter in the dependency constructor is optional. However, I believe that users who are using versions higher than 20 of Keycloak will need to specify this parameter.

Here's my Keycloak constructor looks:

new Keycloak([
    'authServerUrl' => getenv('AUTH_SERVER_URL'),
    'realm' => getenv('REALM'),
    'clientId' => getenv('CLIENT_ID'),
    'clientSecret' => getenv('CLIENT_SECRET'),
    'redirectUri' => getenv('REDIRECT_URI'),
    'version' => '21.0.2', # Add this parameter to troubleshoot the issue
]);

After configuring the parameter and making a new request, I was able to confirm that everything is working correctly. Now it's possible to retrieve user information without encountering the Forbidden 403 error . That was causing the request to come empty and generate the error in parse JSON response.

Screenshot of example:

image

I hadn't noticed the version issue, and only understood the situation better after your explanation. I'm very grateful for your feedback and the clarity of your explanation.

OdyX commented 1 year ago

Upon upgrade of our Keycloak server to 21, login with that library suddenly stopped working. This ought to be more robust; especially with a version parameter marked as optional.

pifikusacek commented 1 year ago

Thank you so much for pointing this out. I was facing the same issue and wasn't able to fix that >] With added scope openid it works

mstefan21 commented 11 months ago

Next week I will look at and prepare fix

Phearal commented 10 months ago

Thank you so much, i lost hours trying to solve the problem after the system team upgraded their Keycloak version...

matteo-piazza-exm commented 1 month ago

openid

Yes, I managed to make things work using these parameters:

$provider->getAccessToken('password', [
    'username' => 'username',
    'password' => 'password',
    'scope' => 'openid',    // <=== required, in my case
    'version' => '25.0.1'
]);