Coder Social home page Coder Social logo

oauth2-keycloak's Introduction

Keycloak Provider for OAuth 2.0 Client

Latest Version Software License Build Status Coverage Status Quality Score Total Downloads

This package provides Keycloak OAuth 2.0 support for the PHP League's OAuth 2.0 Client.

Installation

To install, use composer:

composer require stevenmaguire/oauth2-keycloak

Usage

Usage is the same as The League's OAuth client, using \Stevenmaguire\OAuth2\Client\Provider\Keycloak as the provider.

Use authServerUrl to specify the Keycloak server URL. You can lookup the correct value from the Keycloak client installer JSON under auth-server-url, eg. http://localhost:8080/auth.

Use realm to specify the Keycloak realm name. You can lookup the correct value from the Keycloak client installer JSON under resource, eg. master.

Authorization Code Flow

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    'authServerUrl'         => '{keycloak-server-url}',
    'realm'                 => '{keycloak-realm}',
    'clientId'              => '{keycloak-client-id}',
    'clientSecret'          => '{keycloak-client-secret}',
    'redirectUri'           => 'https://example.com/callback-url',
    'encryptionAlgorithm'   => 'RS256',                             // optional
    'encryptionKeyPath'     => '../key.pem'                         // optional
    'encryptionKey'         => 'contents_of_key_or_certificate'     // optional
    'version'               => '20.0.1',                            // 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;

// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {

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

} else {

    // Try to get an access token (using the authorization coe grant)
    try {
        $token = $provider->getAccessToken('authorization_code', [
            'code' => $_GET['code']
        ]);
    } catch (Exception $e) {
        exit('Failed to get access token: '.$e->getMessage());
    }

    // Optional: Now you have a token you can look up a users profile data
    try {

        // We got an access token, let's now get the user's details
        $user = $provider->getResourceOwner($token);

        // Use these details to create a new profile
        printf('Hello %s!', $user->getName());

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

    // Use this to interact with an API on the users behalf
    echo $token->getToken();
}

Refreshing a Token

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    'authServerUrl'     => '{keycloak-server-url}',
    'realm'             => '{keycloak-realm}',
    'clientId'          => '{keycloak-client-id}',
    'clientSecret'      => '{keycloak-client-secret}',
    'redirectUri'       => 'https://example.com/callback-url',
]);

$token = $provider->getAccessToken('refresh_token', ['refresh_token' => $token->getRefreshToken()]);

Handling encryption

If you've configured your Keycloak instance to use encryption, there are some advanced options available to you.

Configure the provider to use the same encryption algorithm

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    // ...
    'encryptionAlgorithm'   => 'RS256',
]);

or

$provider->setEncryptionAlgorithm('RS256');

Configure the provider to use the expected decryption public key or certificate

By key value
$key = "-----BEGIN PUBLIC KEY-----\n....\n-----END PUBLIC KEY-----";
// or
// $key = "-----BEGIN CERTIFICATE-----\n....\n-----END CERTIFICATE-----";

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    // ...
    'encryptionKey'   => $key,
]);

or

$provider->setEncryptionKey($key);
By key path
$keyPath = '../key.pem';

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    // ...
    'encryptionKeyPath'   => $keyPath,
]);

or

$provider->setEncryptionKeyPath($keyPath);

Testing

$ ./vendor/bin/phpunit

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.

oauth2-keycloak's People

Contributors

babeuloula avatar bastnic avatar colq2 avatar giorgioma avatar jgdevweb avatar konstantincodes avatar liquidpl avatar mainick avatar mstefan21 avatar panigrc avatar raehalme avatar settermjd avatar stevenmaguire avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oauth2-keycloak's Issues

Invalid Scope

We used this library to authenticate users via Keycloak but recently the auth flow has faulted. The reason of an error is incorrect scope parameter sent to Keycloak within auth (from Keycloak's log):

16:13:10,768 ERROR [org.keycloak.services] (default task-54) KC-SERVICES0093: Invalid parameter value for: scope

If we take a look at Request URL we found comma between two scopes sent to Keycloak:

http://some-host/auth/realms/lukoil/protocol/openid-connect/auth?state=6295e030c7925245329dc6a2e49f1ff3&scope=name%2Cemail&response_type=code&approval_prompt=auto&redirect_uri=http://some-host&client_id=client

From a Server Administration Guide (https://www.keycloak.org/docs/latest/server_admin/):

The scope parameter contains the string, with the scope values divided by space (which is also the reason why a client scope name cannot contain a space character in it).

If we change source code of a function getDefaultScopes() (https://github.com/stevenmaguire/oauth2-keycloak/blob/master/src/Provider/Keycloak.php#L177) from:

return ['name', 'email'];

to:

return ['profile email'];

then auth flow will be fixed.

Notice the scope 'name' does not exist by default (https://www.keycloak.org/docs/latest/server_admin/#_client_scopes) so we replaced it to 'profile'.

Please check the auth flow with the latest Keycloak release and fix the issue if persists.

Keycloak includes the session token in the URL

I have a Dummy PHP site, and want to integrate the Keycloak SSO to the site's Admin page.
However there are some problems with the URL. After I logged in the admin page, the URL contains the session token.
Is there any option to remove the session from the URL after the login?

Identity and Access Tokens are confused?

Referencing KeyCloak Supported Protocols we have two tokens available:

  1. Identity - email, name, etc
  2. Access - realm, user role mappings, etc

The sample code shows use of getAccessToken() which leads to the properties I would expect from the identity token including email and name.

What I want are the roles provided to the user through KeyCloak. Have I missed a step here?

Warning: 4.0.0 is incompatible with firebase/php-jwt >= 6.6.0

Unfortunately today I tripped into a problem with incompatible version.
So it seems that in the firebase jwt library in version 6.6.0 and upwards a change in the decode method was introduced where values are passed by reference.

public static function decode(
        string $jwt,
        $keyOrKeyArray,
        stdClass &$headers = null
    ): stdClass {

This is in Version 4.0.0 of the keyycloak not working because the decode method is called with an array. It seems to be fixed in Version 5.0.0.

So when you use this library in 4.0.0 make sure that the php-jwt library is pinned at < 6.6.0.

Update users custom attribute

I'm managed to get custom attribute after authenticate. I would like to further enhance my application to update user's custom attribute. Is it doable with this library?

KC20 Support

Hello,
thanks for the great project.

Since KC20 is released, a lot of breaking changes took place.

Do you have any plans how to migrate the library to work with the new API.

We faced the first issue, that a user is not fetched with the token. We are going on inspecting the issues, but I think here will be some work.

Best regards

Token verification failed

Bearer realm="master", error="invalid_token", error_description="Token verification failed"

provider

        $provider = new \Drupal\moduleform\Controller\Provider([
            'authServerUrl'         => 'http://kc_app:8080',
            'realm'                 => 'master',
            'clientId'              => 'same',
            'clientSecret'          => '8nOJEQv2O0h6ORtxy6G17zZiRTwBCaUj',
            'redirectUri'           => 'http://localhost:5080/login',
            'encryptionAlgorithm'   => 'RS256',                             // optional
        ]);

jwt

looks like this error https://gist.github.com/des1roer/b7240dfcb299c7d91881f7908b92cbe8

response + request - https://gist.github.com/des1roer/b7240dfcb299c7d91881f7908b92cbe8

keycloack container

version: '3'

volumes:
  postgres_data:
    driver: local

services:
  kc_db:
    container_name: kc_postgres
    image: postgres:15.1-alpine
    # volumes:
    #   - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: password
    ports:
      - '${EXTERNAL_DB_PORT}:5432'
  kc_app:
    container_name: keycloak
    image: quay.io/keycloak/keycloak:20.0.1
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://kc_db:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: password
      # DB_SCHEMA: public
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
      # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
      #JDBC_PARAMS: "ssl=true"
    command: start-dev
    ports:
      - '${KC_PORT}:8080'
    depends_on:
      - kc_db
    networks:
      - bd_external
      - default

networks:
  bd_external:
    external: true

php container

version: '3'
services:
    nginx:
        image: nginx:latest
        ports:
            - "${NGINX_PORT}:80"
        volumes:
            - ./hosts:/etc/nginx/conf.d
            - ../:/var/www
            - ./logs/nginx:/var/log/nginx
        links:
            - php
        networks:
            - internal
            - default
            - bd_external
    php:
        build: ./php
        environment:
            XDEBUG_CONFIG: 'remote_host=${XDEBUG_REMOTE_HOST:-host.docker.internal} remote_enable=1'
        volumes:
            - ../:/var/www
        networks:
            - internal
            - default
            - bd_external
        extra_hosts:
            - "host.docker.internal:host-gateway"

networks:
    bd_external:
        external: true

client

{
  "clientId": "same",
  "name": "",
  "description": "",
  "rootUrl": "http://localhost:5080",
  "adminUrl": "",
  "baseUrl": "http://localhost:5080",
  "surrogateAuthRequired": false,
  "enabled": true,
  "alwaysDisplayInConsole": true,
  "clientAuthenticatorType": "client-secret",
  "secret": "8nOJEQv2O0h6ORtxy6G17zZiRTwBCaUj",
  "redirectUris": [
    "http://localhost:5080/login"
  ],
  "webOrigins": [
    "*"
  ],
  "notBefore": 0,
  "bearerOnly": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": false,
  "publicClient": false,
  "frontchannelLogout": true,
  "protocol": "openid-connect",
  "attributes": {
    "oidc.ciba.grant.enabled": "false",
    "client.secret.creation.time": "1669120316",
    "backchannel.logout.session.required": "true",
    "display.on.consent.screen": "false",
    "oauth2.device.authorization.grant.enabled": "true",
    "backchannel.logout.revoke.offline.tokens": "false",
    "request.uris": "",
    "token.endpoint.auth.signing.alg": "HS256",
    "consent.screen.text": "",
    "frontchannel.logout.url": "",
    "backchannel.logout.url": "",
    "login_theme": "",
    "acr.loa.map": "{}",
    "use.jwks.url": "false",
    "logoUri": "",
    "policyUri": "",
    "tosUri": "",
    "access.token.signed.response.alg": "",
    "id.token.signed.response.alg": "",
    "id.token.encrypted.response.alg": "",
    "id.token.encrypted.response.enc": "",
    "user.info.response.signature.alg": "",
    "request.object.signature.alg": "",
    "request.object.encryption.alg": "",
    "request.object.encryption.enc": "",
    "request.object.required": "",
    "authorization.signed.response.alg": "",
    "authorization.encrypted.response.alg": "",
    "authorization.encrypted.response.enc": "",
    "exclude.session.state.from.auth.response": "",
    "use.refresh.tokens": "true",
    "client_credentials.use_refresh_token": "false",
    "token.response.type.bearer.lower-case": "false",
    "access.token.lifespan": "",
    "client.session.idle.timeout": "",
    "client.session.max.lifespan": "",
    "client.offline.session.idle.timeout": "",
    "client.offline.session.max.lifespan": "",
    "tls-client-certificate-bound-access-tokens": false,
    "pkce.code.challenge.method": "",
    "require.pushed.authorization.requests": "false"
  },
  "authenticationFlowBindingOverrides": {
    "direct_grant": "776a184f-b92d-46c0-9959-64dc85dd5fee",
    "browser": ""
  },
  "fullScopeAllowed": true,
  "nodeReRegistrationTimeout": -1,
  "defaultClientScopes": [
    "web-origins",
    "acr",
    "roles",
    "profile",
    "email"
  ],
  "optionalClientScopes": [
    "address",
    "phone",
    "offline_access",
    "microprofile-jwt"
  ],
  "access": {
    "view": true,
    "configure": true,
    "manage": true
  },
  "authorizationServicesEnabled": false
}

Handling Messages

Hello Steve !
Thank you for this helpfull tool.
Do you know how handle the error/alert showed in keycloak login page ?
I saw that you use exit() but I need show the messages on keycloak login page.
Thank you.

Overwritten encryptionKeyPath

Hello,
I'm using this bundle (v2.1.0) combined with league/oauth2-client (v.2.2.1) and knpuniversity/oauth2-client-bundle (v2.3.0). I have the problem that the config parameter encryptionKeyPath is always overwritten and can not be used for that reason.

As far as I understand this happens:

In the Stevenmaguire\OAuth2\Client\Provider\Keycloak the constructor reads the encryption key file content and puts it in the encryptionKey property. After that the parent constructor League\OAuth2\Client\Provider\AbstractProvider is called. For each option the property will be set with the corresponding value. Thats also the case for the encryptionKey option. So the previous value from encryptionKeyPath will always be overwritten by the encryptionKey value.

Now comes the problem with the knpuniversity/oauth2-client-bundle. In KnpU\OAuth2ClientBundle\DependencyInjection\Providers\KeycloakProviderConfigurator encryption_key is set with default null. So even if you do not have it in your configuration, it is passed as option with value null to the Provider constructors. You end up with encryptionKey null without the content from your encryptionKeyPath in any case.

Bearer-Only Client

I wan't to use this library to secure my PHP backend with a Bearer-Token. Any Request needs to have a header: Authentication: Bearer . I'm able to extract that token already from the request and want to send it to the provider to verify it.

  if (preg_match("/Bearer\s+(.*)$/i", $request->getHeaderLine("Authorization"), $matches)) {
    $token = $matches[1];
    ...

My Keycloak Realm is configured with realm myrealm and it has a clientId backend which is defined as bearer-only.

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    'authServerUrl'         => 'https://keycloak-server/auth',
    'realm'                 => 'myrealm',
    'clientId'              => 'backend',
    'clientSecret'          => 'mysecret'
]);
  
$accessToken = $provider->getAccessToken('authorization_code', ['code' => $token]);
error_log(print_r($accessToken,true));

With curl I call https://keycloak-server/auth/realms/$REALM/protocol/openid-connect/token as another client (frontend) to create a token, then I call my PHP script with that token.

But in getAccessToken, I'm getting an error with

invalid_client: Bearer-only not allowed

The trace is:

/vendor/stevenmaguire/oauth2-keycloak/src/Provider/Keycloak.php","line":192,"trace":"
#0 /vendor/league/oauth2-client/src/Provider/AbstractProvider.php(613): Stevenmaguire\\OAuth2\\Client\\Provider\\Keycloak->checkResponse(Object(GuzzleHttp\\Psr7\\Response), Array)
#1 /vendor/league/oauth2-client/src/Provider/AbstractProvider.php(528): League\\OAuth2\\Client\\Provider\\AbstractProvider->getParsedResponse(Object(GuzzleHttp\\Psr7\\Request))\n
#2 /src/public/v1/libs/OAuthAuthentication.class.php(166): League\\OAuth2\\Client\\Provider\\AbstractProvider->getAccessToken(Object(League\\OAuth2\\Client\\Grant\\AuthorizationCode), Array)

I'm not sure, if this is a Keycloak issue - but a SpringBoot-REST-Controller is working with that clientId. If I change the client to "confidential", that I'm getting a different error.

invalid_grant: Code not valid

Even when it works - the PHP service should be a REST backend without user interaction and in that case the Bearer Token seems to be right to me. What do I miss?

keycloak-2.4.0 / oauth2-keycloak userinfo problem

keycloak version : 2.4.0

Sample php code:
`$app->get('/login', function (Request $request, Response $response) {

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
'authServerUrl' => 'http://keycloak.mvp.tfm.ro/auth',
'realm' => 'TFM',
'clientId' => 'YYYYYYYY',
'clientSecret' => 'XXXXXXXXXXXXXXXXXXXXXX',
'redirectUri' => 'http://tfm.systems/login',
]);

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;

// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state, make sure HTTP sessions are enabled.');
} else {
// Try to get an access token (using the authorization coe grant)
try {
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
} catch (Exception $e) {
exit('Failed to get access token: '.$e->getMessage());
}

// Optional: Now you have a token you can look up a users profile data
try {

    // We got an access token, let's now get the user's details
    $user = $provider->getResourceOwner($token);
    // Use these details to create a new profile
    printf('Hello %s!', $user->getName());

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

`

Error result:
`
Slim Application Error

The application could not run because of the following error:
Details
Type: TypeError
Message: Argument 1 passed to Stevenmaguire\OAuth2\Client\Provider\Keycloak::createResourceOwner() must be of the type array, string given, called in /www/www.tfm.systems/vendor/league/oauth2-client/src/Provider/AbstractProvider.php on line 781
File: /www/www.tfm.systems/vendor/stevenmaguire/oauth2-keycloak/src/Provider/Keycloak.php
Line: 109
Trace

#0 /www/www.tfm.systems/vendor/league/oauth2-client/src/Provider/AbstractProvider.php(781): Stevenmaguire\OAuth2\Client\Provider\Keycloak->createResourceOwner('eyJhbGciOiJSUzI...', Object(League\OAuth2\Client\Token\AccessToken))
#1 /www/www.tfm.systems/public/index.php(46): League\OAuth2\Client\Provider\AbstractProvider->getResourceOwner(Object(League\OAuth2\Client\Token\AccessToken))
#2 [internal function]: Closure->{closure}(Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#3 /www/www.tfm.systems/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php(41): call_user_func(Object(Closure), Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#4 /www/www.tfm.systems/vendor/slim/slim/Slim/Route.php(344): Slim\Handlers\Strategies\RequestResponse->__invoke(Object(Closure), Object(Slim\Http\Request), Object(Slim\Http\Response), Array)
#5 /www/www.tfm.systems/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(116): Slim\Route->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#6 /www/www.tfm.systems/vendor/slim/slim/Slim/Route.php(316): Slim\Route->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#7 /www/www.tfm.systems/vendor/slim/slim/Slim/App.php(438): Slim\Route->run(Object(Slim\Http\Request), Object(Slim\Http\Response))
#8 /www/www.tfm.systems/vendor/slim/slim/Slim/MiddlewareAwareTrait.php(116): Slim\App->__invoke(Object(Slim\Http\Request), Object(Slim\Http\Response))
#9 /www/www.tfm.systems/vendor/slim/slim/Slim/App.php(332): Slim\App->callMiddlewareStack(Object(Slim\Http\Request), Object(Slim\Http\Response))
#10 /www/www.tfm.systems/vendor/slim/slim/Slim/App.php(293): Slim\App->process(Object(Slim\Http\Request), Object(Slim\Http\Response))
#11 /www/www.tfm.systems/public/index.php(60): Slim\App->run()
#12 {main}
`

This is caused when the " User Info Signed Response Algorithm " is set to RS256 . If is set to none works as expected.

Return Groups in Access Token

I am trying to get the user details after authenticating with Keycloak v21.0.2. I am getting the details with the user authenticated with the client and client scopes. But I am adding a new client scope of Type Group Membership then the code is breaking and giving me errors as "Notice: Undefined index: error_description" and is not returning anything.
Group membership Client scope :
image
image

Error from Symfony :
image

Now if I remove the group client scope and it is returning back the token. I am not sure if this is issue with Keycloak or the oauth-client-bundle which we are using.

User coming from LDAP/AD Directory will be having group information associated and will have access to application based upon the groups only, hence it is mandatory to get the group in the token.

@stevenmaguire/anyone Any help or suggestion will be appreciated.

CVE in Firebase PHP-JWT before 6.0.0

CVE-2021-46743 identifies the following issue:

"In Firebase PHP-JWT before 6.0.0, an algorithm-confusion issue (e.g., RS256 / HS256) exists via the kid (aka Key ID) header, when multiple types of keys are loaded in a key ring. This allows an attacker to forge tokens that validate under the incorrect key. NOTE: this provides a straightforward way to use the PHP-JWT library unsafely, but might not be considered a vulnerability in the library itself."

Breaking changes in v6.0.0 of firebase/php-jwt appear to be relevant to code in /src/Provider/Keycloak.php

Guzzle >= 7 breaks

We're using this package in a WP plugin, and Guzzle 7.x is in use on the site. This causes fatal errors due to a deprecated call in Guzzle 6.x.

Solution: Upgrade theleague/oauth2-client >= 2.5.0. thephpleague/oauth2-client@06c70e6

I'm not sure of the implications of doing this, nor why the current version is locked to < 2.3.0.

Realm does not exist

Good morning. Please can I use this bundle for a "bearer only client" in a rest api in symfony ? Or is it only for public client which have UI for redirection ?
I tried to omit the redirection parameters redirect_route and redirect_params: {} because this is not relevant for a bearer only client or rest microservice but it dosnt work.

when i test on postman i have this error message-> Realm does not exist

thx for your help in advance

Allow redirect without id_token_hint

I think, the last changes in this implementation

if ($this->validateGteVersion('18.0.0')) {
if (isset($options['access_token']) === true) {
$accessToken = $options['access_token'];
$params['id_token_hint'] = $accessToken->getValues()['id_token'];
$params['post_logout_redirect_uri'] = $params['redirect_uri'];
}
unset($params['redirect_uri']);
}

does not represent the current specs on https://openid.net/specs/openid-connect-rpinitiated-1_0.html where it says, that a id_token parameter is recommended but not mandatory. This current implementation does not allow to have the redirect without a token anymore, which is wrong. The line $params['post_logout_redirect_uri'] = $params['redirect_uri']; should be outside the if statement.

Tokens rejected due to: Token (issuer) invalid

I have an issue with user login/access tokens being invalid, due to the issuer.

Related to this stevenmaguire/oauth2-keycloak/issues/43 but in my case, I don't have an issue with network topology, docker, etc., but with multiple domains pointing to the same Keycloak server.

Say, I have two domains pointing to Keycloak, and a single secured application. Depending on some circumstances I redirect users to either DomainA or DomainB pointing to same Keycloak.

The problem is that, because Keycloak sets the iss field and uses the URL that the user logged in, and because I can only set a single auth_server_url on the secured application, all tokens generated on DomainB ie. all users logging in there, will be denied access.

oauth2-keycloak will only accept tokens generated on DomainA ie. what's set for auth_server_url.

Is there a way to set multiple valid issuers or a set of valid auth_server_urls?

Any workarounds for this?

Id_token_hint

What method should I call to get the access_token that contains the id_token?

   if (isset($options['access_token']) === true) {
                $accessToken = $options['access_token'];

                $params['id_token_hint'] = $accessToken->getValues()['id_token'];
                $params['post_logout_redirect_uri'] = $params['redirect_uri'];
            }

Login confirmation

Hi @stevenmaguire , Thanks for your wonderful project. I am newbie to oauth & keycloak. I was playing around & testing it within my php site for signing in with Keycloak users which works. However I have several other sites connected to same Keycloak with same configuration settings and requests coming from other sites are always asks users to login to Keycloak and then redirected back but my php site with oauth2-keycloak asks just one time and later login requests are being automatically granted by Keycloak without asking from the userd. Keycloak asks to login only after logout and then browser was closed. I want Keycloak to ask users to login if they had been logged out at the php site. Can you guys tell me how to go about it?

Logout problem

hey, could You help me with logout option.

$client = $this->clientRegistry->getClient('keycloak');
  $logoutUrl = $client->getOAuth2Provider()->getLogoutUrl();
  $response = $client->getOAuth2Provider()->getRequest('GET',$logoutUrl );

when i click logoutUrl on browser i can logout - but from application not

Token verification failed - Setup with knpuniversity/oauth2-client-bundle, docker compose and Traefik v2

Problem

Has anyone got this package working locally with Docker Compose and Traefik v2? Because I've tried setting this up with the knpuniversity/oauth2-client-bundle, but I keep getting the error that the token verification failed.

IdentityProviderException
HTTP 500 Internal Server Error
invalid_token: Token verification failed

image

Application

I've setup the following in my Symfony 6 (PHP 8.1) app:

config\packages\framework.yaml

  session:
    enabled: true
    handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler
    cookie_secure: auto
    cookie_samesite: lax

config\packages\knpu_oauth2_client.yaml

knpu_oauth2_client:
  http_client_options:
    timeout: 0
    proxy: 'http://keycloak:8080'
    verify: false
  clients:
    keycloak:
      type: keycloak
      client_id: '%env(OAUTH_KEYCLOAK_CLIENT_ID)%'
      client_secret: '%env(OAUTH_KEYCLOAK_CLIENT_SECRET)%'
      redirect_route: '%env(OAUTH_KEYCLOAK_REDIRECT_ROUTE)%'
      redirect_params: { }
      auth_server_url: '%env(OAUTH_KEYCLOAK_URL)%'
      realm: '%env(OAUTH_KEYCLOAK_REALM)%'

config\packages\security.yaml

...
  providers:
    oauth:
      id: knpu.oauth2.user_provider
  firewalls:
    dev:
      pattern: ^/(_(profiler|wdt)|css|images|js)/
      security: false
    main:
      lazy: true
      provider: oauth
      custom_authenticator: App\Security\KeycloakAuthenticator

App\Controller\KeycloakController

namespace App\Controller;

use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class KeycloakController
 */
final class KeycloakController extends AbstractController
{
    #[Route('/connect/keycloak', name: 'connect_keycloak_start')]
    public function connectAction(
        ClientRegistry $clientRegistry
    ): RedirectResponse {
        return $clientRegistry->getClient('keycloak')->redirect(['email'], []);
    }

    #[Route('/connect/keycloak/check', name: 'connect_keycloak_check')]
    public function connectCheckAction(
        Request $request,
        ClientRegistry $clientRegistry
    ) {
    }
}

App\Security\KeycloakAuthenticator

namespace App\Security;

use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Client\Provider\KeycloakClient;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

/**
 * Class KeycloakAuthenticator
 */
class KeycloakAuthenticator extends OAuth2Authenticator
{
    private $clientRegistry;
    private $entityManager;
    private $router;

    /**
     * KeycloakAuthenticator constructor.
     * @param  ClientRegistry  $clientRegistry
     * @param  EntityManagerInterface  $em
     * @param  RouterInterface  $router
     */
    public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $em, RouterInterface $router)
    {
        $this->clientRegistry = $clientRegistry;
        $this->entityManager = $em;
        $this->router = $router;
    }

    /**
     * @param  Request  $request
     * @return bool|null
     */
    public function supports(Request $request): ?bool
    {
        return $request->attributes->get('_route') === 'connect_keycloak_check';
    }

    /**
     * @param  Request  $request
     * @return Passport
     */
    public function authenticate(Request $request): Passport
    {
        /** @var KeycloakClient $client */
        $client = $this->clientRegistry->getClient('keycloak');
        $accessToken = $this->fetchAccessToken($client);

        return new SelfValidatingPassport(
            new UserBadge($accessToken->getToken(), function () use ($accessToken, $client) {
                return $client->fetchUserFromToken($accessToken);
            })
        );
    }

    /**
     * @param  Request  $request
     * @param  TokenInterface  $token
     * @param  string  $firewallName
     * @return Response|null
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return new RedirectResponse($this->router->generate('admin'));
    }

    /**
     * @param  Request  $request
     * @param  AuthenticationException  $exception
     * @return Response|null
     */
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $message = strtr($exception->getMessageKey(), $exception->getMessageData());

        return new Response($message, Response::HTTP_FORBIDDEN);
    }
}

Docker Compose

docker-compose.yml - app

  phpfpm:
    build:
      context: docker/php
      dockerfile: Dockerfile
      args:
        PHP_VERSION: ${PHP_VERSION}
    container_name: app_phpfpm
    user: ${UID}:${GID}
    security_opt:
      - no-new-privileges:true
    restart: always
    environment:
      - PHP_OPCACHE_ENABLE=${OPCACHE_ENABLE}
      - PHP_OPCACHE_VALIDATE_TIMESTAMPS=${OPCACHE_VALIDATE_TIMESTAMPS}
      - PHP_OPCACHE_PRELOAD_ENV=${APP_ENV}
    volumes:
      - .:/app
      - ~/certs:/certs
      - ./docker/php/conf/opcache.ini:/usr/local/etc/php/conf.d/opcache.ini
      - ./docker/php/conf/php.ini:/usr/local/etc/php/conf.d/php.ini
      - ./docker/php/conf/www.conf:/usr/local/etc/php-fpm.d/www.${APP_DOMAIN}.conf
    networks:
      - proxy
      - app-network

  apache:
    build:
      context: docker/apache
      dockerfile: Dockerfile
      args:
        APACHE_VERSION: ${APACHE_VERSION}
    container_name: app_apache
    security_opt:
      - no-new-privileges:true
    restart: always
    volumes:
      - .:/app
      - apache_log:/var/log/apache2
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.${APP_NAME}-apache-secure.entrypoints=websecure"
      - "traefik.http.routers.${APP_NAME}-apache-secure.rule=Host(`${APP_DOMAIN}`, `www.${APP_DOMAIN}`)"
      - "traefik.http.routers.${APP_NAME}-apache-secure.service=${APP_NAME}-apache-service"
      - "traefik.http.routers.${APP_NAME}-apache-secure.tls=true"
      - "traefik.http.routers.${APP_NAME}-apache-secure.middlewares=secure-headers@file"
      - "traefik.http.services.${APP_NAME}-apache-service.loadbalancer.server.port=80"
      - "traefik.docker.network=proxy"
    networks:
      - proxy
      - app-network

docker-compose.yml - keycloak (16.1.0)

  keycloak:
    image: jboss/keycloak:${KEYCLOAK_VERSION}
    container_name: keycloak
    depends_on:
      - keycloak-postgres
    environment:
      DB_VENDOR: postgres
      DB_ADDR: keycloak_postgres
      DB_PORT: 5432
      DB_DATABASE: ${KEYCLOAK_STORAGE_POSTGRES_DATABASE}
      DB_USER: ${KEYCLOAK_STORAGE_POSTGRES_USERNAME}
      DB_PASSWORD: ${KEYCLOAK_STORAGE_POSTGRES_PASSWORD}
      KEYCLOAK_USER: ${KEYCLOAK_USERNAME}
      KEYCLOAK_PASSWORD: ${KEYCLOAK_PASSWORD}
      KEYCLOAK_HOSTNAME: keycloak.${APP_DOMAIN}
      PROXY_ADDRESS_FORWARDING: 'true'
      KEYCLOAK_LOGLEVEL: DEBUG
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.keycloak-secure.entrypoints=websecure"
      - "traefik.http.routers.keycloak-secure.rule=Host(`keycloak.${APP_DOMAIN}`, `www.keycloak.${APP_DOMAIN}`)"
      - "traefik.http.routers.keycloak-secure.service=keycloak-service"
      - "traefik.http.routers.keycloak-secure.tls=true"
      - "traefik.http.services.keycloak-service.loadbalancer.passhostheader=true"
      - "traefik.http.services.keycloak-service.loadbalancer.server.port=8080"
      - "traefik.docker.network=proxy"
    networks:
      - proxy
      - keycloak-network

docker-compose.yml - traefik (2.5)

  traefik:
    image: traefik:v${TRAEFIK_VERSION}
    container_name: traefik
    security_opt:
      - no-new-privileges:true
    ports:
      - 80:80
      - 443:443
      - 8080:8080
    restart: always
    environment:
      CF_API_EMAIL: ${CF_EMAIL}
      CF_API_KEY: ${CF_API_KEY}
    volumes:
      - ./docker/traefik/config/traefik.yml:/traefik.yml:ro
      - ./docker/traefik/config/dynamic:/dynamic:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/localtime:/etc/localtime:ro
      - /usr/share/zoneinfo:/usr/share/zoneinfo:ro
      - ~/certs:/certs
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-secure.entrypoints=websecure"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik.${APP_DOMAIN}`, `www.traefik.${APP_DOMAIN}`)"
      - "traefik.http.routers.traefik-secure.service=api@internal"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.docker.network=proxy"

traefik.yml

api:
  dashboard: true

log:
  format: json
  level: DEBUG

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure

  websecure:
    address: :443

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    watch: true
    network: proxy
  file:
    directory: /dynamic
    watch: true

dynamic/http.yml

http:
  middlewares:
    secure-headers:
      headers:
        frameDeny: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 63072000
        customFrameOptionsValue: SAMEORIGIN
        referrerPolicy: "strict-origin-when-cross-origin"
        customRequestHeaders:
          X-Forwarded-Proto: https
          X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex,"

with proxy set as external network.

Keycloak

I've setup the client as follows and configured the Credentials with basic Client Id and Secret (no signed JWT).

image

When checking the events, only thing that seems different is that the first the IP address being used. The LOGIN action uses the client IP, whereas the CODE_TO_TOKEN action uses the IP of the docker container.
image

No idea if this is related to the token verification failing.

Debug

After trying to debug the authentication progress, I noticed that the access_token that is returned after login, is the same as the one being used to get the users info. So it hasn't changed or anything (which I could image causing the error).

It's already been 3 days of (trying) to debug this but there seems literally no similar cases to be found anywhere, so I'm out of ideas.

Resource owner getters for First & Last name + optional additional data

The resource owner should have getters for these fields. The keycloak OIDC identity provider provides first and last name by default.

If email is not used as username, then we also get the username:
If email verification is specified, then we also get that data:
image

And a common piece of data (especially when integrating with something like Drupal) is a user picture.
image
image

getEmailVerified()
getFamilyName()
getGivenName
getPicture()
getPreferredUsername()

Make some methods of Keycloak class public

It would be helpful if the following methods would be public.
Additionally I'm not seeing a reason to be private or protected.

private function getBaseLogoutUrl()

protected function getBaseUrlWithRealm()

bug on getAccessToken()

(1/1) FatalThrowableErrorType error:

Argument 1 passed to GuzzleHttp\Client::send() must be an instance of GuzzleHttp\Message\RequestInterface, instance of GuzzleHttp\Psr7\Request given, called in \vendor\league\oauth2-client\src\Provider\AbstractProvider.php on line 608
in Client.php line 158
at Client->send(object(Request))in AbstractProvider.php line 608
at AbstractProvider->getResponse(object(Request))in AbstractProvider.php line 621
at AbstractProvider->getParsedResponse(object(Request))in AbstractProvider.php line 537
at AbstractProvider->getAccessToken(object(AuthorizationCode), array('code' => '3856ae58-b33f-4a7c-85b7-c92304f10ec6.44938cc4-7ba6-479d-926c-a0ac16bbaba2.09abc999-3e8b-42af-bce2-b5ea06117874'))in AdminLoginOauthAuthenticationController.php line 89

Cant take userName

Hello Steven, I would like to know if you have another example how to get data returned from keycloak server. I've following your example step-by-step to make authentication and everything is working fine, but when I try to obtain user data it returns this error "Undefined index name".

My code (I'm putting thid code on welcome.blade.php):

'http://my_server/auth', 'realm' => 'myRealm', 'clientId' => 'myClientId', 'clientSecret' => 'mySecret', 'redirectUri' => 'http://localhost:8080/laravel/larazero/public/index.php', ]); //If we don't have an authorization code then get one if (!isset($_GET['code'])) { $authUrl = $provider->getAuthorizationUrl(); $_SESSION['oauth2state'] = $provider->getState(); header('Location: '.$authUrl); exit; // Check given state against previously stored one to mitigate CSRF attack } elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); exit('Invalid state, make sure HTTP sessions are enabled.'); } else { // Try to get an access token (using the authorization coe grant) try { $token = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); } catch (Exception $e) { exit('Failed to get access token: '.$e->getMessage()); } // Optional: Now you have a token you can look up a users profile data try { // We got an access token, let's now get the user's details $user = $provider->getResourceOwner($token); // Use these details to create a new profile printf('Hello %s!\n
', $user->getName()); } catch (Exception $e) { exit('Failed to get resource owner: '.$e->getMessage()); } // Use this to interact with an API on the users behalf echo $token->getToken(); } ?>

Keycloak 18 drop support for redirect_uri

Since Keycloak 18.0.0 the OpenID Connect Logout has changed:
https://www.keycloak.org/2022/04/keycloak-1800-released.html#_openid_connect_logout

The redirect_uri parameter in logout url is not allowed anymore.
Instead post_logout_redirect_uri can be used.

I tested following quickfix successfully with keycloak 18.0.0:

    public function getLogoutUrl(array $options = [])
    {
        $base = $this->getBaseLogoutUrl();
        $params = $this->getAuthorizationParameters($options);
        
        # quickfix
        $params['post_logout_redirect_uri'] = $params['redirect_uri'];
        unset($params['redirect_uri']);
        
        $query = $this->getAuthorizationQuery($params);
        return $this->appendQuery($base, $query);
    }

Additionally, a parameter with the id_token can be included to omit a logout confirmation.

Handling rotating keys in Keycloak

Hi guys!
I'm not sure this is the right channel to place this question, since it isn't really an issue, and I apologize if that's not the case.
But, anyway, reading the docs of Keycloak Java Adapter, I was worried with this part:

realm-public-key
PEM format of the realm public key. You can obtain this from the administration console.
This is OPTIONAL and it’s not recommended to set it. If not set, the adapter will download
this from Keycloak and it will always re-download it when needed (eg. Keycloak rotate it’s keys).
However if realm-public-key is set, then adapter will never download new keys from Keycloak, so when Keycloak rotate it’s keys, adapter will break.

https://www.keycloak.org/docs/latest/securing_apps/index.html#_java_adapter_config

I'm working with PHP and using your package (thank you very much 🥇 ), so I was wondering if you guys are handling the rotating keys as the Java Adapter (download it from Keycloak and re-download it when needed).
If not, it would be a nice feature to add.

Thank you, and keep up the good work!

Expose logout URL

It would be useful to expose the logout URL similarly to getBaseAuthorizationUrl.

Keycloak API

I'm trying to use the Keycloak REST API with your library, and I don't know if it's possible. I'm looking throught the main methods and trying to connect to the API but I don't get any response...

Is supported the access to the API in this library?

Thank you very much!

Failed to parse JSON response

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)

README.md Authorization Code Flow

$provider = new Stevenmaguire\OAuth2\Client\Provider\Keycloak([
    'authServerUrl'         => '{keycloak-server-url}',
    'realm'                 => '{keycloak-realm}',
    'clientId'              => '{keycloak-client-id}',
    'clientSecret'          => '{keycloak-client-secret}',
    'redirectUri'           => 'https://example.com/callback-url',
    'encryptionAlgorithm'   => 'RS256',                             // optional
    'encryptionKeyPath'     => '../key.pem'                         // optional
    'encryptionKey'         => 'contents_of_key_or_certificate'     // optional
    'version'               => '20.0.1',                            // optional
]);

'version' => '20.0.1', // optional

since 18.0.0 this is required. I just spent 3 days tracking down a 'Invalid response received from Authorization Server. Expected JSON.' error when I finally found that scope:openid was not being added due to requiring this version. Since 20.0.0 it is even more important.

No longer maintained?

Is this project dead? Multiple issues are open without any responses, and there's also pull requests open for known issue with no responses. Does anyone know any good alternatives for this project?

check-sso

How can I use this library to check if any user is logged into keycloak? By using check-sso ?

Change firebase/php-jwt: to support 4.0 and 5.0, league/oauth2-client 2.0 <2.4.0

Hi stevenmaguire,

First ok all, thanks of your project and it is really useful. Recently I'm tried integrate oauth2-keycloak into suitecrm, the composer failed due to firebase/php-jwt strict to 4.0, and league/oauth2-client till 2.3.0. It is old and people is using php-jwt 5.0, and oauth2-client 2.4.0.

I'd manually put oauth2-keycloak into suitecrm vendor folder, and resolve the autoload manually. It work perfectly in firebase/php-jwt. So, can you enlarge the php-jwt support to 5.0, and oauth2-client to 2.4.0?

After your enlarge the support I can make the keycloak available to suitecrm. Thanks

I can't fetchUserFromToken

Hi, when i'm trying to fetUserFromToken, i got an error :

Invalid response received from Authorization Server. Expected JSON.

My token is valid before :

[League\OAuth2\Client\Token\AccessToken](file:///D:/Paul%20DOS%20SANTOS/Bureau/ApsideCSE/vendor/league/oauth2-client/src/Token/AccessToken.php#L25) {#581 ▼
  #accessToken: "
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJpRko2YnA5Q0cwQW5HbXE5NVpRbGw5UGFsQVJxVU81YzN4aGpjWFlkZ3pBIn0.eyJleHAiOjE3MDkyOTM5NjksImlhdCI6MTcwOTI5MzkwOSwiYXV0aF90aW1lIjoxNzA5MjkzNDUyLCJqdGkiOiIzYTljOTZhNy1jMTcxLTQ3YjMtODA1MS1mY2JlMzU1NzY2NDkiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwOTAvcmVhbG1zL21hc3RlciIsImF1ZCI6WyJtYXN0ZXItcmVhbG0iLCJhY2NvdW50Il0sInN1YiI6IjQ2OGRkMWMxLWFkMDUtNGYyZS1hNmYzLTk2OWZlZTU1MzFjNSIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFwc2lkZS1jb25uZWN0Iiwic2Vzc2lvbl9zdGF0ZSI6Ijg4Nzg1OGRmLWQyMmItNGEyYS04ZTVmLWI2NWE2MjBhZWJkNiIsImFjciI6IjAiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9sb2NhbGhvc3Q6ODAwMC8qIiwiaHR0cDovL2xvY2FsaG9zdDo4MDAwLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImNyZWF0ZS1yZWFsbSIsImRlZmF1bHQtcm9sZXMtbWFzdGVyIiwib2ZmbGluZV9hY2Nlc3MiLCJhZG1pbiIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsibWFzdGVyLXJlYWxtIjp7InJvbGVzIjpbInZpZXctcmVhbG0iLCJ2aWV3LWlkZW50aXR5LXByb3ZpZGVycyIsIm1hbmFnZS1pZGVudGl0eS1wcm92aWRlcnMiLCJpbXBlcnNvbmF0aW9uIiwiY3JlYXRlLWNsaWVudCIsIm1hbmFnZS11c2VycyIsInF1ZXJ5LXJlYWxtcyIsInZpZXctYXV0aG9yaXphdGlvbiIsInF1ZXJ5LWNsaWVudHMiLCJxdWVyeS11c2VycyIsIm1hbmFnZS1ldmVudHMiLCJtYW5hZ2UtcmVhbG0iLCJ2aWV3LWV2ZW50cyIsInZpZXctdXNlcnMiLCJ2aWV3LWNsaWVudHMiLCJtYW5hZ2UtYXV0aG9yaXphdGlvbiIsIm1hbmFnZS1jbGllbnRzIiwicXVlcnktZ3JvdXBzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiI4ODc4NThkZi1kMjJiLTRhMmEtOGU1Zi1iNjVhNjIwYWViZDYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIn0.FPa-uhYGv1vhsyn5MhiPM7wqYqW_orwWDjHB4QsfBVKvNokNCBA84xLUvnIlAyQcvPUotwmi84KZROtE_ZU7TTtBhhPqf8fQgrs1fkjrPMrqZqRFHGoleYqTg6uyXp_IWH_8Tp-9JX0fN88wKTjaYoKywf23WiUHk5R73Rv304rzNuVH9urGXuwsa27CSORHd5v0IrbILV_w_mii_h7FK6uuXY6Ish17yyBE5TA1JJESE4w1C9JjVCjrJfxFWfeEwbsw2_hOo2_H9VUKHS_66Cq2eRqmilBX9y9NXZ_UZOOk1tVc4__6Kb0Q3xmhHO39thhBc3t-9tiPWkAuvNrhng
 ◀
"
  #expires: 1709293969
  #refreshToken: "
eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI3MTE5MGIzYS1hOGQxLTQyMTItYTI0OC02ZDNmM2M4Yjk3YWQifQ.eyJleHAiOjE3MDkyOTU3MDksImlhdCI6MTcwOTI5MzkwOSwianRpIjoiNDcwYzY4NzQtOWE1Yi00YTJmLThiN2EtMzkyMDljYTk5YWU1IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDkwL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwOTAvcmVhbG1zL21hc3RlciIsInN1YiI6IjQ2OGRkMWMxLWFkMDUtNGYyZS1hNmYzLTk2OWZlZTU1MzFjNSIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJhcHNpZGUtY29ubmVjdCIsInNlc3Npb25fc3RhdGUiOiI4ODc4NThkZi1kMjJiLTRhMmEtOGU1Zi1iNjVhNjIwYWViZDYiLCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiI4ODc4NThkZi1kMjJiLTRhMmEtOGU1Zi1iNjVhNjIwYWViZDYifQ.W-hzuo5rtY4hk1Sn9Ioe9wv8uBSkzRVi-Ay7GeQ_Rlo
 ◀
"
  #resourceOwnerId: null
  #values: array:5 [▼
    "refresh_expires_in" => 1800
    "token_type" => "Bearer"
    "not-before-policy" => 0
    "session_state" => "887858df-d22b-4a2a-8e5f-b65a620aebd6"
    "scope" => "email profile"
  ]
}

I use Keycloak 23.0.7 with Docker with this conf :

KC_HOSTNAME=localhost
KC_PORT=8090
KC_REALM_NAME=master
KC_LOG_LEVEL=INFO
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=keycloak

I use WAMP last version on windows with php 8.3.2

I use Symfony 7.0 with :
stevenmaguire/oauth2-keycloak v5.1.0
knpuniversity/oauth2-client-bundle v2.18.1

I think something wrong, with other project with same configuration but with Keycloak 16.1 this work fine.

I change the keycloak server url and removed /auth (v18 of keycloak)

I've got the redirect to login screen, i can login, but after when i'm back to symfony on my authenticate function from my Authenticator, i can't fetchUserFromToken.

Someone can help me ?

thank

Upgrade to 5.0.0: Missing Changelog or Upgrade Document

Hello, I use this Bundle for the implementation of authentication via Keycloak in conjunction with knpuniversity/oauth2-client-bundle.

Im am trying to upgrade this package from 4.0.0 to 5.0.0, expecting BC breaks, because of the major version update.
Unfortunately the CHANGELOG.md seems to not be maintained since version 2.10 and there is also no UPGRADE.md guideline.

Id be very thankful for an upgrade guide, a list of breaking changes between v4 and v5 or an update to the changelog

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.