diff --git a/app/Models/OauthSetting.php b/app/Models/OauthSetting.php
index 08e08d85b..74ddebd75 100644
--- a/app/Models/OauthSetting.php
+++ b/app/Models/OauthSetting.php
@@ -29,6 +29,8 @@ class OauthSetting extends Model
case 'authentik':
case 'clerk':
return filled($this->client_id) && filled($this->client_secret) && filled($this->base_url);
+ case 'keycloak':
+ return filled($this->client_id) && filled($this->client_secret) && filled($this->base_url) && filled($this->tenant);
default:
return filled($this->client_id) && filled($this->client_secret);
}
diff --git a/bootstrap/helpers/socialite.php b/bootstrap/helpers/socialite.php
index fd3fbe74b..39c147bdc 100644
--- a/bootstrap/helpers/socialite.php
+++ b/bootstrap/helpers/socialite.php
@@ -33,6 +33,17 @@ function get_socialite_provider(string $provider)
return Socialite::driver($provider)->setConfig($authentik_clerk_config);
}
+ if ($provider == 'keycloak') {
+ $keycloak_config = new \SocialiteProviders\Manager\Config(
+ $oauth_setting->client_id,
+ $oauth_setting->client_secret,
+ $oauth_setting->redirect_uri,
+ ['base_url' => $oauth_setting->base_url, 'realms' => $oauth_setting->tenant],
+ );
+
+ return Socialite::driver('keycloak')->setConfig($keycloak_config);
+ }
+
if ($provider == 'zitadel') {
$zitadel_config = new \SocialiteProviders\Manager\Config(
$oauth_setting->client_id,
diff --git a/composer.json b/composer.json
index 0aeb91958..c2263a88c 100644
--- a/composer.json
+++ b/composer.json
@@ -43,6 +43,7 @@
"socialiteproviders/discord": "^4.2",
"socialiteproviders/google": "^4.1",
"socialiteproviders/infomaniak": "^4.0",
+ "socialiteproviders/keycloak": "^5.3",
"socialiteproviders/microsoft-azure": "^5.2",
"socialiteproviders/zitadel": "^4.2",
"spatie/laravel-activitylog": "^4.10.2",
diff --git a/composer.lock b/composer.lock
index 38e2373fd..93268d11c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "710c697fd96f4388646963daf6f10304",
+ "content-hash": "71773b93dcde4806f9d5e261f9a6b2b5",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -6706,6 +6706,56 @@
},
"time": "2024-11-20T05:42:36+00:00"
},
+ {
+ "name": "socialiteproviders/keycloak",
+ "version": "5.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/SocialiteProviders/Keycloak.git",
+ "reference": "87d13f8a411a6f8f5010ecbaff9aedd4494863e4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/SocialiteProviders/Keycloak/zipball/87d13f8a411a6f8f5010ecbaff9aedd4494863e4",
+ "reference": "87d13f8a411a6f8f5010ecbaff9aedd4494863e4",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "php": "^7.4 || ^8.0",
+ "socialiteproviders/manager": "~4.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "SocialiteProviders\\Keycloak\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Oleg Kuchumov",
+ "email": "voenniy@gmail.com"
+ }
+ ],
+ "description": "Keycloak OAuth2 Provider for Laravel Socialite",
+ "keywords": [
+ "keycloak",
+ "laravel",
+ "oauth",
+ "provider",
+ "socialite"
+ ],
+ "support": {
+ "docs": "https://socialiteproviders.com/keycloak",
+ "issues": "https://github.com/socialiteproviders/providers/issues",
+ "source": "https://github.com/socialiteproviders/providers"
+ },
+ "time": "2023-04-10T05:50:49+00:00"
+ },
{
"name": "socialiteproviders/manager",
"version": "v4.8.1",
diff --git a/config/services.php b/config/services.php
index 6a21cda18..07724711d 100644
--- a/config/services.php
+++ b/config/services.php
@@ -67,4 +67,12 @@ return [
'base_url' => env('ZITADEL_BASE_URL'),
],
+ 'keycloak' => [
+ 'base_url' => env('KEYCLOAK_BASE_URL'),
+ 'realms' => env('KEYCLOAK_REALM', 'master'),
+ 'client_id' => env('KEYCLOAK_CLIENT_ID'),
+ 'client_secret' => env('KEYCLOAK_CLIENT_SECRET'),
+ 'redirect' => env('KEYCLOAK_REDIRECT_URI'),
+ ],
+
];
diff --git a/database/migrations/2025_02_07_000000_add_keycloak_to_oauth_settings.php b/database/migrations/2025_02_07_000000_add_keycloak_to_oauth_settings.php
new file mode 100644
index 000000000..035e54359
--- /dev/null
+++ b/database/migrations/2025_02_07_000000_add_keycloak_to_oauth_settings.php
@@ -0,0 +1,27 @@
+ 'keycloak',
+ 'enabled' => false,
+ ]);
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ \App\Models\OauthSetting::where('provider', 'keycloak')->delete();
+ }
+};
diff --git a/resources/views/livewire/settings-oauth.blade.php b/resources/views/livewire/settings-oauth.blade.php
index 7650a5654..4ddce3568 100644
--- a/resources/views/livewire/settings-oauth.blade.php
+++ b/resources/views/livewire/settings-oauth.blade.php
@@ -32,15 +32,16 @@
@endif
- @if ($oauth_setting['provider'] == 'google')
+ @if ($oauth_setting['provider'] == 'google' || $oauth_setting['provider'] == 'keycloak')
+ helper="{{ $oauth_setting['provider'] == 'google' ? 'Optional parameter that supplies a hosted domain (HD) to Google, which
triggers a login hint to be displayed on the OAuth screen with this domain.
Google Documentation' : 'The Realm name for your Keycloak instance. Default is \'master\'.' }}"
+ label="{{ $oauth_setting['provider'] == 'google' ? 'Tenant' : 'Realm' }}" />
@endif
@if (
$oauth_setting['provider'] == 'authentik' ||
$oauth_setting['provider'] == 'clerk' ||
$oauth_setting['provider'] == 'zitadel' ||
+ $oauth_setting['provider'] == 'keycloak' ||
$oauth_setting['provider'] == 'gitlab')