{"id":14983888,"url":"https://github.com/mainick/keycloakclientbundle","last_synced_at":"2025-04-07T12:03:51.921Z","repository":{"id":197975205,"uuid":"699968731","full_name":"mainick/KeycloakClientBundle","owner":"mainick","description":"The KeycloakClientBundle is bundle for Symfony, designed to simplify Keycloak integration into your application in Symfony and provide additional functionality for token management and user information access. It also includes a listener to verify the token on every request.","archived":false,"fork":false,"pushed_at":"2024-11-25T08:59:58.000Z","size":145,"stargazers_count":28,"open_issues_count":1,"forks_count":9,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-25T09:13:48.024Z","etag":null,"topics":["bundle","keycloak-client","oauth2","oauth2-client","php","symfony","symfony-bundle"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mainick.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-03T17:31:20.000Z","updated_at":"2024-11-25T09:00:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"6128f4b8-7e0f-4e89-a01d-662cba2b258e","html_url":"https://github.com/mainick/KeycloakClientBundle","commit_stats":{"total_commits":53,"total_committers":4,"mean_commits":13.25,"dds":0.05660377358490565,"last_synced_commit":"47f30bd77132a8f3df3341a0e843baf3df0e5e7e"},"previous_names":["mainick/keycloakclientbundle"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainick%2FKeycloakClientBundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainick%2FKeycloakClientBundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainick%2FKeycloakClientBundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mainick%2FKeycloakClientBundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mainick","download_url":"https://codeload.github.com/mainick/KeycloakClientBundle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247648976,"owners_count":20972945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bundle","keycloak-client","oauth2","oauth2-client","php","symfony","symfony-bundle"],"created_at":"2024-09-24T14:08:07.711Z","updated_at":"2025-04-07T12:03:51.889Z","avatar_url":"https://github.com/mainick.png","language":"PHP","readme":"KeycloakClientBundle\n====================\n\n[![Latest Version](https://img.shields.io/github/release/mainick/KeycloakClientBundle.svg?style=flat-square)](https://github.com/mainick/KeycloakClientBundle/releases)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)\n[![Total Downloads](https://img.shields.io/packagist/dt/mainick/keycloak-client-bundle.svg?style=flat-square)](https://packagist.org/packages/mainick/keycloak-client-bundle)\n\nThe `KeycloakClientBundle` bundle is a wrapper for the `stevenmaguire/oauth2-keycloak` package,\ndesigned to simplify Keycloak integration into your application in Symfony and provide additional functionality\nfor token management and user information access.\nIt also includes a listener to verify the token on every request.\n\n## Configuration\n\nBefore installing this package, you need to configure it manually.\nYou can do this by creating a `mainick_keycloak_client.yaml` file in the `config/packages` directory of your project\nand adding the following configuration:\n\n```yaml\n# config/packages/mainick_keycloak_client.yaml\n\nmainick_keycloak_client:\n  keycloak:\n    verify_ssl: '%env(bool:IAM_VERIFY_SSL)%'\n    base_url: '%env(IAM_BASE_URL)%'\n    realm: '%env(IAM_REALM)%'\n    client_id: '%env(IAM_CLIENT_ID)%'\n    client_secret: '%env(IAM_CLIENT_SECRET)%'\n    redirect_uri: '%env(IAM_REDIRECT_URI)%'\n    encryption_algorithm: '%env(IAM_ENCRYPTION_ALGORITHM)%'\n    encryption_key: '%env(IAM_ENCRYPTION_KEY)%'\n    encryption_key_path: '%env(IAM_ENCRYPTION_KEY_PATH)%'\n    version: '%env(IAM_VERSION)%'\n```\n\nAdditionally, it's recommended to add the following environment variables to your project's environment file\n(e.g., `.env` or `.env.local`) with the appropriate values for your configuration:\n\n```shell\n###\u003e mainick/keycloak-client-bundle ###\nIAM_VERIFY_SSL=true # Verify SSL certificate\nIAM_BASE_URL='\u003cyour-base-server-url\u003e'  # Keycloak server URL\nIAM_REALM='\u003cyour-realm\u003e' # Keycloak realm name\nIAM_CLIENT_ID='\u003cyour-client-id\u003e' # Keycloak client id\nIAM_CLIENT_SECRET='\u003cyour-client-secret\u003e' # Keycloak client secret\nIAM_REDIRECT_URI='\u003cyour-redirect-uri\u003e' # Keycloak redirect uri\nIAM_ENCRYPTION_ALGORITHM='\u003cyour-algorithm\u003e' # RS256, HS256, etc.\nIAM_ENCRYPTION_KEY='\u003cyour-public-key\u003e' # public key\nIAM_ENCRYPTION_KEY_PATH='\u003cyour-public-key-path\u003e' # public key path\nIAM_VERSION='\u003cyour-version-keycloak\u003e' # Keycloak version\n###\u003c mainick/keycloak-client-bundle ###\n```\n\nMake sure to replace the placeholder values with your actual configuration values.\nOnce you have configured the package and environment variables, you can proceed with the installation.\n\n## Installation\n\nYou can install this package using [Composer](http://getcomposer.org/):\n\n```\ncomposer require mainick/keycloak-client-bundle\n```\n\nThen, enable the bundle by adding it to the list of registered bundles\nin the `config/bundles.php` file of your project:\n\n```php\n// config/bundles.php\n\nreturn [\n    // ...\n    Mainick\\KeycloakClientBundle\\MainickKeycloakClientBundle::class =\u003e ['all' =\u003e true],\n];\n```\n\nBy configuring the package before installation, you ensure that it will be ready to use once installed.\n\n## Usage\n\n### Get the Keycloak client\n\nYou can get the Keycloak client by injecting the `Mainick\\KeycloakClientBundle\\Interface\\IamClientInterface`\ninterface in your controller or service.\n\nTo use it, you need to add the following configuration\nto your `config/services.yaml` file:\n\n```yaml\nservices:\n    Mainick\\KeycloakClientBundle\\Interface\\IamClientInterface:\n        alias: Mainick\\KeycloakClientBundle\\Provider\\KeycloakClient\n```\n\nThen, you can use it in your controller or service:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Service;\n\nuse Mainick\\KeycloakClientBundle\\Interface\\IamClientInterface;\n\nclass IamService\n{\n    public function __construct(\n        private IamClientInterface $iamClient\n    ) {\n    }\n}\n```\n\nPerform the desired operations, such as retrieving additional user claims, assigned roles, associated groups, etc.\n\n\n```php\n// authenticate the user with username and password\n$accessToken = $this-\u003eiamClient-\u003eauthenticate($username, $password);\n\n// authenticate the user with authorization code\n$accessToken = $this-\u003eiamClient-\u003eauthenticateCodeGrant($authorizationCode);\n\n// verify and introspect the token\n$userRepresentation = $this-\u003eiamClient-\u003everifyToken($accessToken);\necho $userRepresentation-\u003eid; // id\necho $userRepresentation-\u003eusername; // username\necho $userRepresentation-\u003eemail; // email\necho $userRepresentation-\u003efirstName; // first name\necho $userRepresentation-\u003elastName; // last name\necho $userRepresentation-\u003ename; // full name\necho $userRepresentation-\u003egroups; // all groups assigned to the user\necho $userRepresentation-\u003erealmRoles; // realm roles assigned to the user\necho $userRepresentation-\u003eclientRoles; // client roles assigned to the user\necho $userRepresentation-\u003eapplicationRoles; // specific client roles assigned to the user\necho $userRepresentation-\u003eattributes; // additional user attributes\n\n// refresh the token\n$accessToken = $this-\u003eiamClient-\u003erefreshToken($accessToken);\n\n// get user info\n$userInfo = $this-\u003eiamClient-\u003euserInfo($accessToken);\necho $userInfo-\u003eid; // id\necho $userInfo-\u003eusername; // username\necho $userInfo-\u003eemail; // email\necho $userInfo-\u003efirstName; // first name\necho $userInfo-\u003elastName; // last name\necho $userInfo-\u003ename; // full name\necho $userInfo-\u003egroups; // all groups assigned to the user\necho $userInfo-\u003erealmRoles; // realm roles assigned to the user\necho $userInfo-\u003eclientRoles; // client roles assigned to the user\necho $userInfo-\u003eapplicationRoles; // specific client roles assigned to the user\necho $userInfo-\u003eattributes; // additional user attributes\n\n// has role\n$hasRole = $this-\u003eiamClient-\u003ehasRole($accessToken, $roleName);\n\n// has any role\n$hasAnyRole = $this-\u003eiamClient-\u003ehasAnyRole($accessToken, $roleNames);\n\n// has all roles\n$hasAllRoles = $this-\u003eiamClient-\u003ehasAllRoles($accessToken, $roleNames);\n\n// has group\n$hasGroup = $this-\u003eiamClient-\u003ehasGroup($accessToken, $groupName);\n\n// has any group\n$hasAnyGroup = $this-\u003eiamClient-\u003ehasAnyGroup($accessToken, $groupNames);\n\n// has all groups\n$hasAllGroups = $this-\u003eiamClient-\u003ehasAllGroups($accessToken, $groupNames);\n\n// has scope\n$hasScope = $this-\u003eiamClient-\u003ehasScope($accessToken, $scopeName);\n\n// has any scope\n$hasAnyScope = $this-\u003eiamClient-\u003ehasAnyScope($accessToken, $scopeNames);\n\n// has all scopes\n$hasAllScopes = $this-\u003eiamClient-\u003ehasAllScopes($accessToken, $scopeNames);\n```\n\n### Token Verification Listener\n\nThe KeycloakClientBundle includes a built-in listener, `TokenAuthListener`, that automatically validates the\nJWT token on every request, ensuring the security and validity of your Keycloak integration.\nThis listener seamlessly handles token validation, allowing you to focus on your application's logic.\n\n#### Using TokenAuthListener\n\nIn your Symfony project, add the `TokenAuthListener` to your `config/services.yaml` file as a registered service\nand tag it as a `kernel.event_listener`. This will enable the listener to trigger on every request.\n\n```yaml\nservices:\n    Mainick\\KeycloakClientBundle\\EventSubscriber\\TokenAuthListener:\n        tags:\n          - { name: kernel.event_listener, event: kernel.request, method: checkValidToken, priority: 0 }\n```\n\n#### Retrieve user information\n\nAdditionally, the `TokenAuthListener` adds an `user` attribute to the Symfony request object,\nwhich contains the `UserRepresentationDTO` object.\n\n```php\n// get the user object from the request\n$user = $request-\u003eattributes-\u003eget('user');\n```\n\nThis `user` attribute contains the user information fetched from the JWT token and is an instance\nof the `UserRepresentationDTO` class.\nThis allows your application to easily access user-related data when processing requests.\n\n#### Excluding Routes from Token Validation\n\n`TokenAuthListener` verifies the token for all incoming requests by default. However,\nif you have specific routes for which you want to exclude token validation,\nyou can do so using the `ExcludeTokenValidationAttribute` attribute.\n\nTo exclude token validation for a particular route, apply the `ExcludeTokenValidationAttribute` to the\ncorresponding controller method.\n\n```php\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\Routing\\Annotation\\Route;\nuse Mainick\\KeycloakClientBundle\\Annotation\\ExcludeTokenValidationAttribute;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController;\n\nclass MyController extends AbstractController\n{\n    #[Route(\"/path/to/excluded/route\", name: \"app.excluded_route\", methods: [\"GET\"])]\n    #[ExcludeTokenValidationAttribute]\n    public function excludedRouteAction(): Response\n    {\n        // This route is excluded from token validation.\n        // ...\n    }\n}\n```\n\nWhen the `ExcludeTokenValidationAttribute` is applied to a method, `TokenAuthListener` will skip token validation\nfor requests to that specific route.\n\n## Symfony Security Configuration\n\n### Bundle configuration\n\nTo use the `KeycloakClientBundle` with Symfony's security component, you need to configure the security system to use the Keycloak client.\n\nFirst you need to add a new section to the bundle configuration file:\n\n```yaml\n# config/packages/mainick_keycloak_client.yaml\nmainick_keycloak_client:\n  security:\n    default_target_route_name: '%env(TARGET_ROUTE_NAME)%'\n```\n\nThen you need to configure the Keycloak redirect uri to the `mainick_keycloak_security_auth_connect_check` bundle route, which redirects to the default route or referer route after successful login.\n\nIt's recommended to change the following environment variable to your project's environment file\n(e.g., `.env` or `.env.local`) with the uri. The same URI must be configured in the Keycloak application client:\n\n```shell\n###\u003e mainick/keycloak-client-bundle ###\nIAM_REDIRECT_URI='https://app.local/auth/keycloak/check'\nTARGET_ROUTE_NAME=app_home\n###\u003c mainick/keycloak-client-bundle ###\n```\n\nBelow is the complete configuration file:\n\n```yaml\n# config/packages/mainick_keycloak_client.yaml\n\nmainick_keycloak_client:\n  keycloak:\n    verify_ssl: '%env(bool:IAM_VERIFY_SSL)%'\n    base_url: '%env(IAM_BASE_URL)%'\n    realm: '%env(IAM_REALM)%'\n    client_id: '%env(IAM_CLIENT_ID)%'\n    client_secret: '%env(IAM_CLIENT_SECRET)%'\n    redirect_uri: '%env(IAM_REDIRECT_URI)%'\n    encryption_algorithm: '%env(IAM_ENCRYPTION_ALGORITHM)%'\n    encryption_key: '%env(IAM_ENCRYPTION_KEY)%'\n    encryption_key_path: '%env(IAM_ENCRYPTION_KEY_PATH)%'\n    version: '%env(IAM_VERSION)%'\n  security:\n      default_target_route_name: '%env(TARGET_ROUTE_NAME)%'\n```\n\n### Route configuration\n\nCreate a new file in ```config/routes/``` to load pre configured bundle routes.\n\n```yaml\n# config/routes/mainick_keycloak_security.yaml\nmainick_keycloak_security_auth_connect:\n  path:       /auth/keycloak/connect\n  controller: Mainick\\KeycloakClientBundle\\Controller\\KeycloakController::connect\n\nmainick_keycloak_security_auth_connect_check:\n  path:       /auth/keycloak/check\n  controller: Mainick\\KeycloakClientBundle\\Controller\\KeycloakController::connectCheck\n\nmainick_keycloak_security_auth_logout:\n  path:       /auth/keycloak/logout\n  controller: Mainick\\KeycloakClientBundle\\Controller\\KeycloakController::logout\n```\n\n### Security configuration\n\nThen you need to configure the security system to use the Keycloak client.\nYou can do this by adding the following configuration to your `config/packages/security.yaml` file to use the bundle's UserProvider:\n\n```yaml\n# config/packages/security.yaml\nproviders:\n  mainick_keycloak_user_provider:\n    id: Mainick\\KeycloakClientBundle\\Security\\User\\KeycloakUserProvider\n```\n\nHere is a simple configuration that restrict access to ```/app/*``` routes only to user with roles \"ROLE_USER\" or \"ROLE_ADMIN\" :\n\n```yaml\n# config/packages/security.yaml\nsecurity:\n  providers:\n    mainick_keycloak_user_provider:\n      id: Mainick\\KeycloakClientBundle\\Security\\User\\KeycloakUserProvider\n\n  firewalls:\n    dev:\n      pattern: ^/(_(profiler|wdt)|css|images|js)/\n      security: false\n\n    auth_connect:\n      pattern: /auth/keycloak/connect\n      security: false\n\n    secured_area:\n      pattern: ^/\n      provider: mainick_keycloak_user_provider\n      entry_point: Mainick\\KeycloakClientBundle\\Security\\EntryPoint\\KeycloakAuthenticationEntryPoint\n      custom_authenticator:\n        - Mainick\\KeycloakClientBundle\\Security\\Authenticator\\KeycloakAuthenticator\n      logout:\n        path: mainick_keycloak_security_auth_logout\n\n  role_hierarchy:\n    ROLE_ADMIN: ROLE_USER\n\n  # Easy way to control access for large sections of your site\n  # Note: Only the *first* access control that matches will be used\n  access_control:\n    - { path: ^/app, roles: ROLE_ADMIN }\n```\n\n### Logout\n\nTo logout the user, you can use the following code:\n\n```php\nuse Symfony\\Component\\HttpFoundation\\RedirectResponse;\nuse Symfony\\Component\\Routing\\Annotation\\Route;\nuse Mainick\\KeycloakClientBundle\\Annotation\\ExcludeTokenValidationAttribute;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController;\n\nclass MyController extends AbstractController\n{\n    #[Route(\"/logout\", name: \"app.logout\", methods: [\"GET\"])]\n    public function logout(): RedirectResponse\n    {\n        return $this-\u003eredirectToRoute('mainick_keycloak_security_auth_logout');\n    }\n}\n```\n\nor create a link in your twig template:\n\n```twig\n\u003ca href=\"{{ path('mainick_keycloak_security_auth_logout') }}\"\u003eLogout\u003c/a\u003e\n```\n\nThis will redirect the user to the Keycloak logout page, where the user will be logged out from the Keycloak server.\n\n### Redirect after login\n\nTo redirect the user to a specific route after login, you can set the `TARGET_ROUTE_NAME` environment variable\nto the desired route name.\n\n```shell\n###\u003e mainick/keycloak-client-bundle ###\nTARGET_ROUTE_NAME=app_home\n###\u003c mainick/keycloak-client-bundle ###\n```\n\nThis will redirect the user to the `app_home` route after a successful login.\n\n### Troubleshooting - You have Access Denied in your browser\n\nIf you have an Access Denied error in your browser, it is maybe because scope roles is misconfigured.\n\nFor correction:\n\n1. Check whether the **ROLE_ADMIN** and **ROLE_USER** roles have been created for the application client.\n2. Click on **Client scopes** on left panel, then **roles**:\n3. Click on **Mappers** tab, then **client roles**:\n4. Disabled **Add to userinfo**, click on **Save**, then enabled **Add to userinfo** and click on **Save**:\n\nPlease check the roles assigned to the user in Keycloak and the roles configured in the Symfony security configuration.\n\n## Running the Tests\n\nInstall the [Composer](http://getcomposer.org/) dependencies:\n\n```bash\ngit clone https://github.com/mainick/KeycloakClientBundle.git\ncd KeycloakClientBundle\ncomposer update\n```\n\nThen run the test suite:\n\n```bash\ncomposer test\n```\n\n## Author\n\n- [Maico Orazio](https://github.com/mainick)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE) for more information.\n\n\n## Contributing\n\nWe welcome your contributions! If you wish to enhance this package or have found a bug,\nfeel free to create a pull request or report an issue in the [issue tracker](https://github.com/mainick/KeycloakClientBundle/issues).\n\nPlease see [CONTRIBUTING](https://github.com/mainick/KeycloakClientBundle/blob/main/CONTRIBUTING.md) for details.\n\n\u003c!-- ## Contributing --\u003e\n\u003c!-- Please see [Contributing](CONTRIBUTING.md) for details. --\u003e\n\n\u003c!-- ## Acknowledgments --\u003e\n\u003c!-- A big thank you to [Steven Maguire](https://github.com/stevenmaguire/oauth2-keycloak) for his `stevenmaguire/oauth2-keycloak` package upon which this wrapper is built. --\u003e\n\n\u003c!-- ## Changelog --\u003e\n\u003c!-- Please see [Changelog](CHANGELOG.md) for details. --\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmainick%2Fkeycloakclientbundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmainick%2Fkeycloakclientbundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmainick%2Fkeycloakclientbundle/lists"}