PHP client to interact with Keycloak's Admin REST API.
Inspired by keycloak/keycloak-nodejs-admin-client.
Install via Composer:
composer require fschmtt/keycloak-rest-api-client-php
Example:
$keycloak = new \Fschmtt\Keycloak\Keycloak(
baseUrl: 'http://keycloak:8080',
username: 'admin',
password: 'admin'
);
$serverInfo = $keycloak->serverInfo()->get();
echo sprintf(
'Keycloak %s is running on %s/%s (%s) with %s/%s since %s and is currently using %s of %s (%s %%) memory.',
$serverInfo->getSystemInfo()->getVersion(),
$serverInfo->getSystemInfo()->getOsName(),
$serverInfo->getSystemInfo()->getOsVersion(),
$serverInfo->getSystemInfo()->getOsArchitecture(),
$serverInfo->getSystemInfo()->getJavaVm(),
$serverInfo->getSystemInfo()->getJavaVersion(),
$serverInfo->getSystemInfo()->getUptime(),
$serverInfo->getMemoryInfo()->getUsedFormated(),
$serverInfo->getMemoryInfo()->getTotalFormated(),
100 - $serverInfo->getMemoryInfo()->getFreePercentage(),
);
will print e.g.
Keycloak 26.0.0 is running on Linux/5.10.25-linuxkit (amd64) with OpenJDK 64-Bit Server VM/11.0.11 since 0 days, 2 hours, 37 minutes, 7 seconds and is currently using 139 MB of 512 MB (28 %) memory.
More examples can be found in the examples directory.
You can register and use custom resources by providing your own representations and resources, e.g.:
class MyCustomRepresentation extends \Fschmtt\Keycloak\Representation\Representation
{
public function __construct(
protected ?string $id = null,
protected ?string $name = null,
) {
}
}
class MyCustomResource extends \Fschmtt\Keycloak\Resource\Resource
{
public function myCustomEndpoint(): MyCustomRepresentation
{
return $this->queryExecutor->executeQuery(
new \Fschmtt\Keycloak\Http\Query(
'/my-custom-endpoint',
MyCustomRepresentation::class,
)
);
}
}
By extending the Resource
class, you have access to both the QueryExecutor
and CommandExecutor
.
The CommandExecutor
is designed to run state-changing commands against the server (without returning a response);
the QueryExecutor
allows fetching resources and representations from the server.
To use your custom resource, pass the fully-qualified class name (FQCN) to the Keycloak::resource()
method.
It provides you with an instance of your resource you can then work with:
$keycloak = new Keycloak(
$_SERVER['KEYCLOAK_BASE_URL'] ?? 'http://keycloak:8080',
'admin',
'admin',
);
$myCustomResource = $keycloak->resource(MyCustomResource::class);
$myCustomRepresentation = $myCustomResource->myCustomEndpoint();
Endpoint | Response | API |
---|---|---|
DELETE /admin/realms/{realm}/attack-detection/brute-force/users |
n/a |
AttackDetection::clear() |
GET /admin/realms/{realm}/attack-detection/brute-force/users/{userId} |
Map | AttackDetection::userStatus() |
DELETE /admin/realms/{realm}/attack-detection/brute-force/users/{userId} |
n/a |
AttackDetection::clearUser() |
Endpoint | Response | API |
---|---|---|
GET /admin/realms/{realm}/clients |
ClientCollection | Clients::all() |
GET /admin/realms/{realm}/clients/{client-uuid} |
Client | Clients::get() |
PUT /admin/realms/{realm}/clients/{client-uuid} |
Client | Clients::update() |
POST /admin/realms/{realm}/clients |
Client | Clients::import() |
GET /admin/realms/{realm}/clients/{clientUuid}/client-secret |
Client | Clients::getClientSecret() |
Endpoint | Response | API |
---|---|---|
GET /admin/realms/{realm}/groups |
GroupCollection | Groups::all() |
GET /admin/realms/{realm}/groups/{id}/children |
GroupCollection | Groups::children() |
GET /admin/realms/{realm}/groups/{id} |
Group | Groups::get() |
PUT /admin/realms/{realm}/groups/{id} |
n/a |
Groups::update() |
POST /admin/realms/{realm}/groups |
n/a |
Groups::create() |
POST /admin/realms/{realm}/groups/{id}/children |
n/a |
Groups::create() |
DELETE /admin/realms/{realm}/groups |
n/a |
Groups::delete() |
Endpoint | Response | API |
---|---|---|
POST /admin/realms |
Realm | Realms::import() |
GET /admin/realms |
RealmCollection | Realms::all() |
PUT /admin/realms/{realm} |
Realm | Realms::update() |
DELETE /admin/realms/{realm} |
n/a |
Realms::delete() |
GET /admin/realms/{realm}/admin-events |
array |
Realms::adminEvents() |
GET /admin/realms/{realm}/keys |
KeysMetadata | Realms::keys() |
DELETE /admin/realms/{realm}/admin-events |
n/a |
Realms::deleteAdminEvents() |
POST /admin/realms/{realm}/clear-keys-cache |
n/a |
Realms::clearKeysCache() |
POST /admin/realms/{realm}/clear-realm-cache |
n/a |
Realms::clearRealmCache() |
POST /admin/realms/{realm}/clear-user-cache |
n/a |
Realms::clearUserCache() |
Endpoint | Response | API |
---|---|---|
GET /admin/realms/{realm}/users |
UserCollection | Users::all() |
POST /admin/realms/{realm}/users |
n/a |
Users::create() |
GET /admin/realms/{realm}/users/{userId} |
User | Users::get() |
PUT /admin/realms/{realm}/users/{userId} |
n/a |
Users::update() |
DELETE /admin/realms/{realm}/users/{userId} |
n/a |
Users::delete() |
GET /admin/realms/{realm}/users |
UserCollection | Users::search() |
PUT /{realm}/users/{id}/groups/{groupId} |
n/a |
Users::joinGroup() |
DELETE /{realm}/users/{id}/groups/{groupId} |
n/a |
Users::leaveGroup() |
GET /{realm}/users/{id}/groups |
GroupCollection | Users::retrieveGroups() |
GET /{realm}/users/{id}/role-mappings/realm |
RoleCollection | Users::retrieveRealmRoles() |
GET /{realm}/users/{id}/role-mappings/realm/available |
RoleCollection | Users::retrieveAvailableRealmRoles() |
POST /{realm}/users/{id}/role-mappings/realm |
n/a |
Users::addRealmRoles() |
DELETE /{realm}/users/{id}/role-mappings/realm |
n/a |
Users::removeRealmRoles() |
PUT /{realm}/users/{id}/execute-actions-email |
n/a |
Users::executeActionsEmail() |
GET /admin/realms/{realm}/users/{userId}/credentials |
CredentialCollection | Users::credentials() |
Endpoint | Response | API |
---|---|---|
GET /admin/realms/{realm}/roles |
RoleCollection | Roles::all() |
GET /admin/realms/{realm}/roles/{roleName} |
Role | Roles::get() |
POST /admin/realms/{realm}/roles |
n/a |
Roles::create() |
DELETE /admin/realms/{realm}/roles/{roleName} |
n/a |
Roles::delete() |
Endpoint | Response | API |
---|---|---|
GET /admin/serverinfo |
ServerInfo | ServerInfo::get() |
Run docker compose up -d keycloak
to start a local Keycloak instance listening on http://localhost:8080.
Run your script (e.g. examples/serverinfo.php) from within the php
container:
docker compose run --rm php php examples/serverinfo.php
analyze
: Run phpstan analysiscs
: Check coding style (PHP CS Fixer)cs:fix
: Fix coding style issues (PHP CS Fixer)test
: Run unit and integration teststest:unit
: Run unit teststest:integration
: Run integration tests (requires a fresh and running Keycloak instance)