PHPackages                             cloudcogsio/oauth2-keycloak - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. cloudcogsio/oauth2-keycloak

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

cloudcogsio/oauth2-keycloak
===========================

Keycloak OAuth2 client

v0.2.1(3y ago)63011MITPHP

Since Aug 3Pushed 1y ago1 watchersCompare

[ Source](https://github.com/cloudcogsio/oauth2-keycloak)[ Packagist](https://packagist.org/packages/cloudcogsio/oauth2-keycloak)[ RSS](/packages/cloudcogsio-oauth2-keycloak/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (3)Dependencies (4)Versions (9)Used By (0)

Keycloak Provider for OAuth 2.0 Client
======================================

[](#keycloak-provider-for-oauth-20-client)

[![GitHub](https://camo.githubusercontent.com/128b6f64253aa6a19341e813568685dfbaadde34b778ec5fb259c9b646fb835c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f636c6f7564636f6773696f2f6f61757468322d6b6579636c6f616b)](https://camo.githubusercontent.com/128b6f64253aa6a19341e813568685dfbaadde34b778ec5fb259c9b646fb835c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f636c6f7564636f6773696f2f6f61757468322d6b6579636c6f616b) [![GitHub last commit](https://camo.githubusercontent.com/f3165b41333c6cc1463d68b9f878e36275e3ef02dc2033eda1a3e6e9169573d8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f636c6f7564636f6773696f2f6f61757468322d6b6579636c6f616b)](https://camo.githubusercontent.com/f3165b41333c6cc1463d68b9f878e36275e3ef02dc2033eda1a3e6e9169573d8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f636c6f7564636f6773696f2f6f61757468322d6b6579636c6f616b)

This package provides Keycloak OAuth 2.0 support for the PHP League's [OAuth 2.0 Client](https://github.com/thephpleague/oauth2-client).

The client uses Keycloak's `.well-known` services endpoint to query the OpenID Provider Metadata for autodiscovery of relevant endpoints for authorization, tokens and public keys for token introspection.

Installation
------------

[](#installation)

To install, use composer:

```
composer require cloudcogsio/oauth2-keycloak

```

Usage
-----

[](#usage)

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

### Configuration via Keycloak OIDC JSON file

[](#configuration-via-keycloak-oidc-json-file)

The client can be configured by passing the Keycloak OIDC JSON file that can be downloaded from your Keycloak server.

1. Go to your Keycloak Admin
2. Select the "Clients" option
3. Select the Client ID of the required client
4. Select the "Installation" tab
5. In the "Format Option" dropdown, choose "Keycloak OIDC JSON"
6. Download. (Default filename is "keycloak.json")

When using the Keycloak OIDC JSON file, only the file and a redirectUri is required to setup the client.

#### Provider Configuration with Keycloak OIDC JSON (keycloak.json)

[](#provider-configuration-with-keycloak-oidc-json-keycloakjson)

```
$provider = new Keycloak([
    'config' => 'keycloak.json',
    'redirectUri' => 'https://example.com/callback-url'
]);
```

### Configuration via Options

[](#configuration-via-options)

The client can also be configured without a Keycloak OIDC JSON file by passing (at minimum) the `authServerUrl` and `realm` options required for endpoint autodiscovery.

You will still need to reference the OIDC JSON configuration in Keycloak to retrieve the values for `clientId` and `clientSecret`. These would be the `resource` and `credentials->secret`.

#### Provider Configuration with `authServerUrl` and `realm` options

[](#provider-configuration-with-authserverurl-and-realm-options)

```
$provider = new Keycloak([
    'authServerUrl' => 'http://localhost:8080/auth/',
    'realm' => 'demo-realm',
    'clientId' => '{keycloak-resource}',
    'clientSecret' => '{keycloak-credentials-secret}',
    'redirectUri' => 'https://example.com/callback-url'
]);
```

### Authorization Code Flow

[](#authorization-code-flow)

Assuming `$provider` was configured as outlined via one of the methods above.

```
// If we don't have an authorization code then get one
if (!isset($_GET['code'])) {

    // Fetch the authorization URL from the provider;
    $authorizationUrl = $provider->getAuthorizationUrl();

    // Get the state generated for you and store it to the session.
    $_SESSION['oauth2state'] = $provider->getState();

    // Redirect the user to the authorization URL.
    header('Location: ' . $authorizationUrl);
    exit;

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

    if (isset($_SESSION['oauth2state'])) {
        unset($_SESSION['oauth2state']);
    }

    exit('Invalid state');

} else {

    try {

        // Try to get an access token using the authorization code grant.
        $accessToken = $provider->getAccessToken('authorization_code', [
            'code' => $_GET['code']
        ]);

        // We have an access token, which we may use in authenticated
        // requests against the service provider's API.
        echo 'Access Token: ' . $accessToken->getToken() . "";
        echo 'Refresh Token: ' . $accessToken->getRefreshToken() . "";
        echo 'Expired in: ' . $accessToken->getExpires() . "";
        echo 'Already expired? ' . ($accessToken->hasExpired() ? 'expired' : 'not expired') . "";

        // Using the access token, we may look up details about the
        // resource owner.
        $resourceOwner = $provider->getResourceOwner($accessToken);

        var_export($resourceOwner->toArray());

        // The provider provides a way to get an authenticated API request for
        // the service, using the access token; it returns an object conforming
        // to Psr\Http\Message\RequestInterface.
        $request = $provider->getAuthenticatedRequest(
            'GET',
            'https://service.example.com/resource',
            $accessToken
        );

    } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {

        // Failed to get the access token or user details.
        exit($e->getMessage());

    }
}
```

### Refreshing a Token

[](#refreshing-a-token)

```
if ($existingAccessToken->hasExpired()) {
    $newAccessToken = $provider->getAccessToken('refresh_token', [
        'refresh_token' => $existingAccessToken->getRefreshToken()
    ]);

    // Purge old access token and store new access token to your data store.
}
```

### Client Logout

[](#client-logout)

The client provides a method to conveniently process a logout action.

A redirect URI can be passed to the method or the `redirectUri` option of the client will be used for redirection. The URI must be configured in the "*Valid Redirect URIs*" field of the client definition in Keycloak.

```
$url = "https://example.com/logout-url-redirect";
$provider->logoutAndRedirect($url);
```

### Resource Owner Password Credentials Grant

[](#resource-owner-password-credentials-grant)

> 🛑 **DANGER!** We advise against using this grant type if the service provider supports the authorization code grant type (see above), as this reinforces the [password anti-pattern](https://agentile.com/the-password-anti-pattern), allowing users to think it’s okay to trust third-party applications with their usernames and passwords.

That said, there are use-cases where the resource owner password credentials grant is acceptable and useful.

```
try {

    // Try to get an access token using the resource owner password credentials grant.
    $accessToken = $provider->getAccessToken('password', [
        'username' => 'myuser',
        'password' => 'mysupersecretpassword'
    ]);

	$resourceOwner = $provider->getResourceOwner($accessToken);

	var_export($resourceOwner->toArray());

} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {

    // Failed to get the access token
    exit($e->getMessage());

}
```

### Client Credentials Grant

[](#client-credentials-grant)

When your application acts on its own behalf to access resources it controls or owns in a service provider, it may use the *client credentials* grant type.

The client credentials grant type is best when storing the credentials for your application privately and never exposing them (e.g., through the web browser, etc.) to end-users. This grant type functions like the resource owner password credentials grant type, but it does not request a user’s username or password. It uses only the client ID and client secret issued to your client by the service provider.

```
try {

    // Try to get an access token using the client credentials grant.
    $accessToken = $provider->getAccessToken('client_credentials');

} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {

    // Failed to get the access token
    exit($e->getMessage());

}
```

Additional Notes
----------------

[](#additional-notes)

### OpenID Connect Discovery endpoint

[](#openid-connect-discovery-endpoint)

By default, this client uses the `.well-known/openid-configuration` endpoint to discover all other endpoints for the Keycloak server once the `authServerUrl` and `realm` options are supplied to create the client.

This is handled by the `cloudcogsio\oauth2-openid-connect-discovery` library. See

```
// Get the discovered configurations from the provider instance
$discovered = $provider->Discovery();

// Access standard OpenID Connect configuration via supported methods
$issuer = $discovered->getIssuer();
$supported_grants = $discovered->getGrantTypesSupported();
$authorization_endpoint = $discovered->getAuthorizationEndpoint();

// Or overloading for Keycloak specific configuration
$check_session_iframe = $discovered->check_session_iframe;

// Cast to string to obtain the raw JSON discovery response
// All available properties for overloading can be seen in the JSON object.
$json_string = (string) $discovered;
```

### Keycloak Public Key(s)

[](#keycloak-public-keys)

During endpoint discovery, the Keycloak realm public key(s) are retrieved and cached locally. This is needed to decode the access token which is then added to the `\Cloudcogs\OAuth2\Client\Provider\Keycloak\ResourceOwner` object as additional values.

#### Caching of Public Keys

[](#caching-of-public-keys)

Caching of JWKs are handled by an instance of `\Laminas\Cache\Storage\Adapter\FileSystem` which is installed with `cloudcogsio\oauth2-openid-connect-discovery`.

You can provide your own instance of a `\Laminas\Cache\Storage\Adapter\*` to handle storage of the Keycloak realm's public key.

### Token Introspection

[](#token-introspection)

By default, the accessToken is decoded locally using the cached public keys. Decoded data is populated and made available in the `\Cloudcogs\OAuth2\Client\Provider\Keycloak\ResourceOwner` object.

This is performed automatically by the client and requires no additional configuration.

#### Token Introspection via Keycloak Server

[](#token-introspection-via-keycloak-server)

All tokens issued by the Keycloak server (accessToken, refreshToken etc.) can be introspected using the Keycloak token introspection endpoint.

The client provides an ` introspectToken(string $token)` method to carry out this operation.

```
// Decode the access token
$access_token = $AccessToken->getToken();
$data = $provider->introspectToken($access_token);

// Decode the refresh token
$refresh_token = $AccessToken->getRefreshToken();
$data = $provider->introspectToken($refresh_token);
```

Custom Access Token Class
-------------------------

[](#custom-access-token-class)

The [` custom-access-token`](https://github.com/cloudcogsio/oauth2-keycloak/tree/custom-access-token) branch of this repository implements a custom `\Cloudcogs\OAuth2\Client\Provider\Keycloak\AccessToken` class that extends the base `\League\OAuth2\Client\Token\AccessToken` class.

Keycloak provides a `refresh_expires_in` property This custom class adds additional methods that checks and detects the validity of the `refreshToken`. The theory of operation is the same as that provided by the base class for checking and detecting the validity of the `accessToken`.

`AccessToken.php`

```
namespace Cloudcogs\OAuth2\Client\Provider\Keycloak;

use League\OAuth2\Client\Token\AccessToken as LeagueAccessToken;

class AccessToken extends LeagueAccessToken
{
    protected $refresh_expires;

    public function __construct(array $options)
    {
        parent::__construct($options);

        /**
         * Determine if the refresh token expires and set expiry time
         */
        if (array_key_exists("refresh_expires_in", $options))
        {
            if (!is_numeric($options['refresh_expires_in'])) {
                throw new \InvalidArgumentException('refresh_expires_in value must be an integer');
            }

            $this->refresh_expires = $options['refresh_expires_in'] != 0 ? $this->getTimeNow() + $options['refresh_expires_in'] : 0;
        }
    }

    public function getRefreshExpires()
    {
        return $this->refresh_expires;
    }

    public function hasRefreshExpired()
    {
        $expires = $this->getRefreshExpires();

        if (empty($expires)) {
            throw new \RuntimeException('"refresh_expires" is not set on the token');
        }

        return $expires < time();
    }
}
```

#### NOTE: At this time a custom AccessToken class is not supported by the base AbstractProvider class of `thephpleague/oauth2-client`.

[](#note-at-this-time-a-custom-accesstoken-class-is-not-supported-by-the-base-abstractprovider-class-of-thephpleagueoauth2-client)

Method signature changes are required before custom Access Token classes (such as the one provided above) can be used. See [thephpleague/oauth2-client#897](https://github.com/thephpleague/oauth2-client/issues/897)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](https://github.com/cloudcogsio/oauth2-keycloak/blob/master/LICENSE.md) for more information.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance29

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~204 days

Total

3

Last Release

1342d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1d2ff1bf8c9106dd0a4a8962cfc90c3450e288f5bc7abe69f0aa44d8e0761022?d=identicon)[cloudcogs](/maintainers/cloudcogs)

---

Top Contributors

[![cloudcogsio](https://avatars.githubusercontent.com/u/66295280?v=4)](https://github.com/cloudcogsio "cloudcogsio (40 commits)")

---

Tags

oauthoauth2openid-connectoauth2keycloakcloudcogscloudcogs.io

### Embed Badge

![Health badge](/badges/cloudcogsio-oauth2-keycloak/health.svg)

```
[![Health](https://phpackages.com/badges/cloudcogsio-oauth2-keycloak/health.svg)](https://phpackages.com/packages/cloudcogsio-oauth2-keycloak)
```

###  Alternatives

[google/auth

Google Auth Library for PHP

1.4k272.7M162](/packages/google-auth)[stevenmaguire/oauth2-keycloak

Keycloak OAuth 2.0 Client Provider for The PHP League OAuth2-Client

2275.9M27](/packages/stevenmaguire-oauth2-keycloak)[amocrm/amocrm-api-library

amoCRM API Client

182728.5k6](/packages/amocrm-amocrm-api-library)[simplesamlphp/simplesamlphp-module-oidc

A SimpleSAMLphp module adding support for the OpenID Connect protocol

5016.9k1](/packages/simplesamlphp-simplesamlphp-module-oidc)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
