You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用stevenmaguire/oauth2-keycloak对接Keycloak22.01获取资源所有者出错

问题:PHP 7.4 对接 Keycloak 22.01 获取资源所有者时JSON解析错误

环境与依赖配置

composer.json 内容:

{
    "require": {
        "stevenmaguire/oauth2-keycloak": "^5.0"
    }
}

报错信息

Uncaught UnexpectedValueException: Failed to parse JSON response:
Syntax error in
/opt/lampp/htdocs/Demo/vendor/league/oauth2-client/src/Provider/AbstractProvider.php:645
Stack trace:
#0 /opt/lampp/htdocs/Demo/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(686):
League\OAuth2\Client\Provider\AbstractProvider->parseJson(NULL)
#1 /opt/lampp/htdocs/Demo/vendor/stevenmaguire/oauth2-keycloak/src/Provider/Keycloak.php(378):
League\OAuth2\Client\Provider\AbstractProvider->parseResponse(Object(GuzzleHttp\Psr7\Response))
#2 /opt/lampp/htdocs/Demo/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(626):
Stevenmaguire\OAuth2\Client\Provider\Keycloak->parseResponse(Object(GuzzleHttp\Psr7\Response))
#3 /opt/lampp/htdocs/Demo/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(784):
League\OAuth2\Client\Provider\AbstractProvider->getParsedResponse(Object(GuzzleHttp\Psr7\Request))
#4 /opt/lampp/htdocs/Demo/vendor/stevenmaguire/oauth2-keycloak/src/Provider/Keycloak.php(271):
League\OAuth2\Client\Provider\AbstractProvider->getParsedResponse(Object(GuzzleHttp\Psr7\Request))
in /opt/lampp/htdocs/Demo/vendor/league/oauth2-client/src/Provider/AbstractProvider.php on line 645

尝试的代码

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    'authServerUrl'         => 'http://localhost:8080',
    'realm'                 => 'Demo',
    'clientId'              => 'email',
    'clientSecret'          => '{keycloak-client-secret}',
    'redirectUri'           => 'http://localhost/Demo/',
    'encryptionAlgorithm'   => 'RS256',                             // optional
]);

if (!isset($_GET['code'])) {
    // If we don't have an authorization code then get one
    $authUrl = $provider->getAuthorizationUrl();
    $_SESSION['oauth2state'] = $provider->getState();
    header('Location: '.$authUrl);
    exit;

} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {

    unset($_SESSION['oauth2state']);
    exit('Invalid state, make sure HTTP sessions are enabled.');

} else {

    $token = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
    ]);
  
    $user = $provider->getResourceOwner($token);
    print_r($user);
    try {
    } catch (Exception $e) {
        exit('Failed to get access token: '.$e->getMessage());

    }

    try {

        $user = $provider->getResourceOwner($token);

        print_r($provider);

    } catch (Exception $e) {
        exit('Failed to get resource owner: '.$e->getMessage());
    }

    echo $token->getToken();
}

排查与解决步骤

  • 检查用户信息端点响应:报错显示解析NULL内容,说明请求Keycloak的/realms/Demo/protocol/openid-connect/userinfo接口返回空或非JSON。手动用调试工具带上获取到的AccessToken调用该接口,确认返回格式是否为标准JSON。
  • 验证Keycloak客户端权限:在Keycloak后台的Demo Realm中,进入email客户端的Client Scopes标签页,确保添加了profile、email等必要的OpenID Connect scope并设为默认勾选;同时在Settings标签页确认客户端Access Type与代码配置匹配(confidential需填clientSecret,public无需clientSecret)。
  • 修正代码结构:原代码在try块外提前调用getResourceOwner会直接抛出异常无法被捕获,调整为将所有认证逻辑放入try块:
    session_start(); // 确保开启会话
    try {
        $provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
            'authServerUrl'         => 'http://localhost:8080',
            'realm'                 => 'Demo',
            'clientId'              => 'email',
            'clientSecret'          => '{your-real-client-secret}',
            'redirectUri'           => 'http://localhost/Demo/',
        ]);
    
        if (!isset($_GET['code'])) {
            $authUrl = $provider->getAuthorizationUrl();
            $_SESSION['oauth2state'] = $provider->getState();
            header('Location: ' . $authUrl);
            exit;
        } elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
            unset($_SESSION['oauth2state']);
            exit('无效的state,请确保HTTP会话已启用。');
        }
    
        $token = $provider->getAccessToken('authorization_code', [
            'code' => $_GET['code']
        ]);
        $user = $provider->getResourceOwner($token);
        
        print_r($user->toArray()); // 输出用户信息数组
        echo '<br>Access Token: ' . $token->getToken();
    } catch (Exception $e) {
        exit('认证失败: ' . $e->getMessage());
    }
    
  • 升级客户端库版本:stevenmaguire/oauth2-keycloak ^5.0 对Keycloak 22的适配可能存在问题,尝试升级到最新稳定版,执行composer require stevenmaguire/oauth2-keycloak:^7.0更新依赖。
  • 调试请求细节:添加Guzzle调试选项,查看请求和响应的详细内容定位问题:
    $provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
        // 原有配置
        'guzzleOptions' => [
            'debug' => fopen('php://stdout', 'w'),
        ],
    ]);
    

内容的提问来源于stack exchange,提问作者Abhishek Poddar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 23:32:15