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/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index 9163d595c..3bd308bba 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -11,6 +11,7 @@ use SocialiteProviders\Google\GoogleExtendSocialite;
use SocialiteProviders\Infomaniak\InfomaniakExtendSocialite;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\Zitadel\ZitadelExtendSocialite;
+use SocialiteProviders\Keycloak\KeycloakExtendSocialite;
class EventServiceProvider extends ServiceProvider
{
@@ -23,6 +24,7 @@ class EventServiceProvider extends ServiceProvider
GoogleExtendSocialite::class.'@handle',
InfomaniakExtendSocialite::class.'@handle',
ZitadelExtendSocialite::class.'@handle',
+ KeycloakExtendSocialite::class.'@handle',
],
];
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 d4fb1eb8e..e7baee6c1 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.11.0",
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/database/seeders/OauthSettingSeeder.php b/database/seeders/OauthSettingSeeder.php
index 2e5e6fcc4..f4d32c780 100644
--- a/database/seeders/OauthSettingSeeder.php
+++ b/database/seeders/OauthSettingSeeder.php
@@ -24,6 +24,7 @@ class OauthSettingSeeder extends Seeder
'google',
'authentik',
'infomaniak',
+ 'keycloak',
'zitadel',
]);
diff --git a/lang/en.json b/lang/en.json
index a81e1ee68..5329e0245 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -9,6 +9,7 @@
"auth.login.gitlab": "Login with Gitlab",
"auth.login.google": "Login with Google",
"auth.login.infomaniak": "Login with Infomaniak",
+ "auth.login.keycloak": "Login with Keycloak",
"auth.login.zitadel": "Login with Zitadel",
"auth.already_registered": "Already registered?",
"auth.confirm_password": "Confirm password",
diff --git a/lang/fr.json b/lang/fr.json
index d98a1ebc8..554f689d9 100644
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -9,6 +9,8 @@
"auth.login.gitlab": "Connexion avec Gitlab",
"auth.login.google": "Connexion avec Google",
"auth.login.infomaniak": "Connexion avec Infomaniak",
+ "auth.login.keycloak": "Connexion avec Keycloak",
+ "auth.login.zitadel": "Connexion avec Zitadel",
"auth.already_registered": "Déjà enregistré ?",
"auth.confirm_password": "Confirmer le mot de passe",
"auth.forgot_password_link": "Mot de passe oublié ?",
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')