diff --git a/apps/maarch_entreprise/xml/keycloakConfig.xml b/apps/maarch_entreprise/xml/keycloakConfig.xml
index 5c67686d90cd54d9982eb78edd993fd9032a019e..0e6d13f5aea0fde0fbe083a27cb2054f11846785 100644
--- a/apps/maarch_entreprise/xml/keycloakConfig.xml
+++ b/apps/maarch_entreprise/xml/keycloakConfig.xml
@@ -4,8 +4,9 @@
     <REALM></REALM>
     <CLIENT_ID></CLIENT_ID>
     <CLIENT_SECRET></CLIENT_SECRET>
-    <REDIRECT_URI>http://demo.maarchcourrier.com/apps/maarch_entreprise/index.php?display=true&amp;page=login</REDIRECT_URI> <!-- Should be the url of Maarch Courrier's login page -->
+    <REDIRECT_URI>http://demo.maarchcourrier.com/dist/index.html#/login</REDIRECT_URI> <!-- Should be the url of Maarch Courrier's login page -->
     <ENCRYPTION_ALGORITHM></ENCRYPTION_ALGORITHM>
     <ENCRYPTION_KEY_PATH></ENCRYPTION_KEY_PATH>
     <ENCRYPTION_KEY></ENCRYPTION_KEY>
+    <SCOPE></SCOPE>
 </ROOT>
diff --git a/apps/maarch_entreprise/xml/login_method.xml b/apps/maarch_entreprise/xml/login_method.xml
index b185b6d5e13e26ca1599cff06e8c8582c4f05d28..8124b63e3ab329f0a9ecb506679bd8c9aa00d3bc 100755
--- a/apps/maarch_entreprise/xml/login_method.xml
+++ b/apps/maarch_entreprise/xml/login_method.xml
@@ -20,8 +20,6 @@
     </METHOD>
     <METHOD>
         <ID>keycloak</ID>
-        <NAME>Keycloak</NAME>
-        <SCRIPT>keycloakConnect.php</SCRIPT>
         <ENABLED>false</ENABLED>
     </METHOD>
     <METHOD>
diff --git a/src/core/controllers/AuthenticationController.php b/src/core/controllers/AuthenticationController.php
index 397c807dce2446f12dcbe2bf49203bcabbfcdbc7..373740298fe4e18e8bb9696927d726efd9694881 100755
--- a/src/core/controllers/AuthenticationController.php
+++ b/src/core/controllers/AuthenticationController.php
@@ -26,6 +26,7 @@ use SrcCore\models\AuthenticationModel;
 use SrcCore\models\CoreConfigModel;
 use SrcCore\models\PasswordModel;
 use SrcCore\models\ValidatorModel;
+use Stevenmaguire\OAuth2\Client\Provider\Keycloak;
 use User\models\UserModel;
 
 class AuthenticationController
@@ -58,16 +59,27 @@ class AuthenticationController
             $port = (string)$casConfiguration->WEB_CAS_PORT;
             $uri = (string)$casConfiguration->WEB_CAS_CONTEXT;
             $authUri = "https://{$hostname}:{$port}{$uri}/login?service=" . UrlController::getCoreUrl() . 'dist/index.html#/login';
+        } elseif ($loggingMethod['id'] == 'keycloak') {
+            $keycloakConfig = CoreConfigModel::getKeycloakConfiguration();
+            $provider = new Keycloak($keycloakConfig);
+            $authUri = $provider->getAuthorizationUrl(['scope' => $keycloakConfig['scope']]);
+            $keycloakState = $provider->getState();
         }
 
-        return $response->withJson([
+        $return = [
             'instanceId'        => $hashedPath,
             'applicationName'   => $appName,
             'loginMessage'      => $parameter['param_value_string'] ?? null,
             'changeKey'         => $encryptKey == 'Security Key Maarch Courrier #2008',
             'authMode'          => $loggingMethod['id'],
             'authUri'           => $authUri
-        ]);
+        ];
+
+        if (!empty($keycloakState)) {
+            $return['keycloakState'] = $keycloakState;
+        }
+
+        return $response->withJson($return);
     }
 
     public function getValidUrl(Request $request, Response $response)
@@ -263,6 +275,16 @@ class AuthenticationController
             if (!AuthenticationController::isUserAuthorized(['login' => $login])) {
                 return $response->withStatus(403)->withJson(['errors' => 'Authentication Failed']);
             }
+        } elseif ($loggingMethod['id'] == 'keycloak') {
+            $queryParams = $request->getQueryParams();
+            $authenticated = AuthenticationController::keycloakConnection(['code' => $queryParams['code']]);
+            if (!empty($authenticated['errors'])) {
+                return $response->withStatus(401)->withJson(['errors' => $authenticated['errors']]);
+            }
+            $login = strtolower($authenticated['login']);
+            if (!AuthenticationController::isUserAuthorized(['login' => $login])) {
+                return $response->withStatus(403)->withJson(['errors' => 'Authentication unauthorized']);
+            }
         } else {
             return $response->withStatus(403)->withJson(['errors' => 'Logging method unauthorized']);
         }
@@ -312,10 +334,14 @@ class AuthenticationController
     {
         $loggingMethod = CoreConfigModel::getLoggingMethod();
 
+        $res = ['logoutUrl' => null];
         if ($loggingMethod['id'] == 'cas') {
             $res = AuthenticationController::casDisconnection();
+        } elseif ($loggingMethod['id'] == 'keycloak') {
+            $res = AuthenticationController::keycloakDisconnection();
         }
-        return $response->withJson(['logoutUrl' => $res['logoutUrl'], 'redirectUrl' => $res['redirectUrl']]);
+
+        return $response->withJson(['logoutUrl' => $res['logoutUrl']]);
     }
 
     private static function standardConnection(array $args)
@@ -461,7 +487,69 @@ class AuthenticationController
         \phpCAS::setFixedServiceURL(UrlController::getCoreUrl() . 'dist/index.html');
         \phpCAS::setNoClearTicketsFromUrl();
         $logoutUrl = \phpCAS::getServerLogoutURL();
-        return ['logoutUrl' => $logoutUrl, 'redirectUrl' => UrlController::getCoreUrl() . 'dist/index.html'];
+        return ['logoutUrl' => $logoutUrl];
+    }
+
+    private static function keycloakConnection(array $args)
+    {
+        $keycloakConfig = CoreConfigModel::getKeycloakConfiguration();
+
+        if (empty($keycloakConfig) || empty($keycloakConfig['authServerUrl']) || empty($keycloakConfig['realm']) || empty($keycloakConfig['clientId']) || empty($keycloakConfig['clientSecret']) || empty($keycloakConfig['redirectUri'])) {
+            return ['errors' => 'Keycloak not configured'];
+        }
+
+        $provider = new Keycloak($keycloakConfig);
+
+        try {
+            $token = $provider->getAccessToken('authorization_code', ['code' => $args['code']]);
+        } catch (\Exception $e) {
+            return ['errors' => 'Authentication Failed'];
+        }
+
+        try {
+            // We got an access token, let's now get the user's details
+            $user = $provider->getResourceOwner($token);
+
+            $login = $user->getId();
+            $keycloakAccessToken = $token->getToken();
+
+            $userMaarch = UserModel::getByLogin(['login' => $login, 'select' => ['id', 'external_id']]);
+
+            if (empty($userMaarch)) {
+                return ['errors' => 'Authentication Failed'];
+            }
+
+            $userMaarch['external_id'] = json_decode($userMaarch['external_id'], true);
+            $userMaarch['external_id']['keycloakAccessToken'] = $keycloakAccessToken;
+            $userMaarch['external_id'] = json_encode($userMaarch['external_id']);
+
+            UserModel::updateExternalId(['id' => $userMaarch['id'], 'externalId' => $userMaarch['external_id']]);
+
+            return ['login' => $login];
+        } catch (\Exception $e) {
+            return ['errors' => 'Authentication Failed'];
+        }
+    }
+
+    private static function keycloakDisconnection()
+    {
+        $keycloakConfig = CoreConfigModel::getKeycloakConfiguration();
+
+        $provider = new Keycloak($keycloakConfig);
+
+        $externalId = UserModel::getById(['id' => $GLOBALS['id'], 'select' => ['external_id']]);
+        $externalId = json_decode($externalId['external_id'], true);
+        $accessToken = $externalId['keycloakAccessToken'];
+        unset($externalId['keycloakAccessToken']);
+        UserModel::update([
+            'set'   => ['external_id' => json_encode($externalId)],
+            'where' => ['id = ?'],
+            'data'  => [$GLOBALS['id']]
+        ]);
+
+        $url = $provider->getLogoutUrl(['client_id' => $keycloakConfig['clientId'], 'refresh_token' => $accessToken]);
+
+        return ['logoutUrl' => $url];
     }
 
     public function getRefreshedToken(Request $request, Response $response)
diff --git a/src/core/models/CoreConfigModel.php b/src/core/models/CoreConfigModel.php
index fca2e40f58b5c4861aea9af1d229edc9662456a4..d8e16c0d4f4bef6c9f343d58f0d7cadcba794819 100755
--- a/src/core/models/CoreConfigModel.php
+++ b/src/core/models/CoreConfigModel.php
@@ -335,6 +335,17 @@ class CoreConfigModel
                 $keycloakConfig['encryptionAlgorithm'] = (string)$loadedXml->ENCRYPTION_ALGORITHM;
                 $keycloakConfig['encryptionKeyPath']   = (string)$loadedXml->ENCRYPTION_KEY_PATH;
                 $keycloakConfig['encryptionKey']       = (string)$loadedXml->ENCRYPTION_KEY;
+                $keycloakConfig['scope']               = (string)$loadedXml->SCOPE;
+
+                if (empty($keycloakConfig['encryptionAlgorithm'])) {
+                    $keycloakConfig['encryptionAlgorithm'] = null;
+                }
+                if (empty($keycloakConfig['encryptionKeyPath'])) {
+                    $keycloakConfig['encryptionKeyPath'] = null;
+                }
+                if (empty($keycloakConfig['encryptionKey'])) {
+                    $keycloakConfig['encryptionKey'] = null;
+                }
             }
         }
 
diff --git a/src/frontend/app/login/login.component.html b/src/frontend/app/login/login.component.html
index 1cd2f086472b5a1a341f210686e9c48c8e459e0f..7b35d8fe65483647110e0d2e868625a28f5920f1 100644
--- a/src/frontend/app/login/login.component.html
+++ b/src/frontend/app/login/login.component.html
@@ -6,11 +6,11 @@
                 <div style="color: white;font-size: 14px;" [innerHTML]="loginMessage | safeHtml"></div>
                 <p style="color: white;font-size: 14px;font-weight: bold;">{{applicationName}}</p>
                 <div style="padding-left: 30px;padding-right: 30px;">
-                    <mat-form-field *ngIf="['cas'].indexOf(authService.authMode) === -1" class="input-row login" appearance="outline" style="padding-bottom: 0px;">
+                    <mat-form-field *ngIf="['cas', 'keycloak'].indexOf(authService.authMode) === -1" class="input-row login" appearance="outline" style="padding-bottom: 0px;">
                         <input id="login" name="login" matInput [placeholder]="this.translate.instant('lang.id')" formControlName="login"
                             type="text">
                     </mat-form-field>
-                    <mat-form-field *ngIf="['cas'].indexOf(authService.authMode) === -1" class="input-row" appearance="outline">
+                    <mat-form-field *ngIf="['cas', 'keycloak'].indexOf(authService.authMode) === -1" class="input-row" appearance="outline">
                         <input id="password" name="password" matInput [placeholder]="this.translate.instant('lang.password')" type="password"
                             formControlName="password">
                         <mat-hint align="end" *ngIf="authService.authMode === 'standard'"><a
@@ -19,7 +19,7 @@
                                 class="infoLogin">{{'lang.' + authService.authMode + 'Enabled' | translate}}</span></mat-hint>
                     </mat-form-field>
                 </div>
-                <div *ngIf="['cas'].indexOf(authService.authMode) > -1" class="alert-message alert-message-info" role="alert" style="max-width: 100%;">
+                <div *ngIf="['cas', 'keycloak'].indexOf(authService.authMode) > -1" class="alert-message alert-message-info" role="alert" style="max-width: 100%;">
                     {{'lang.' + authService.authMode + 'Enabled' | translate}}
                 </div>
                 <button id="submit" type="submit" mat-stroked-button [disabled]="loginForm.invalid || loading"
diff --git a/src/frontend/app/login/login.component.ts b/src/frontend/app/login/login.component.ts
index 7ef3a4fee88a6aefccaa65f39447140d5854d708..a2883d2da0b060a40ce71f4110e5a136c230cb2d 100644
--- a/src/frontend/app/login/login.component.ts
+++ b/src/frontend/app/login/login.component.ts
@@ -120,6 +120,13 @@ export class LoginComponent implements OnInit {
                 this.authService.authMode = data.authMode;
                 this.authService.authUri = data.authUri;
 
+                if (this.authService.authMode === 'keycloak') {
+                    const keycloakState = this.localStorage.get('keycloakState');
+                    if (keycloakState === null || keycloakState === 'null') {
+                        this.localStorage.save('keycloakState', data.keycloakState);
+                    }
+                }
+
                 this.initConnection();
             }),
             finalize(() => this.showForm = true),
@@ -146,9 +153,25 @@ export class LoginComponent implements OnInit {
         if (['cas', 'keycloak'].indexOf(this.authService.authMode) > -1) {
             this.loginForm.disable();
             this.loginForm.setValidators(null);
-            const regex = /ticket=[.]*/g;
-            if (window.location.search.match(regex) !== null) {
+            const regexCas = /ticket=[.]*/g;
+            const regexKeycloak = /code=[.]*/g;
+            if (window.location.search.match(regexCas) !== null || window.location.search.match(regexKeycloak) !== null) {
                 const ssoToken = window.location.search.substring(1, window.location.search.length);
+
+                const regexKeycloakState = /state=[.]*/g;
+                if (ssoToken.match(regexKeycloakState) !== null) {
+                    const params = new URLSearchParams(window.location.search.substring(1));
+                    const keycloakState = this.localStorage.get('keycloakState');
+                    const paramState = params.get('state');
+
+                    this.localStorage.save('keycloakState', null);
+
+                    if (keycloakState !== paramState && keycloakState !== null) {
+                        window.location.href = this.authService.authUri;
+                        return;
+                    }
+                }
+
                 window.history.replaceState({}, document.title, window.location.pathname + window.location.hash);
                 this.onSubmit(`?${ssoToken}`);
             } else {
diff --git a/src/frontend/service/auth.service.ts b/src/frontend/service/auth.service.ts
index 251fc73f2442c0e34994b6706639b7278312bf25..d980b410e40914e7ecb2926b077b5da6dc4860b6 100644
--- a/src/frontend/service/auth.service.ts
+++ b/src/frontend/service/auth.service.ts
@@ -102,7 +102,7 @@ export class AuthService {
         this.http.get('../rest/authenticate/logout').pipe(
             tap(async (data: any) => {
                 this.redirectAfterLogout(cleanUrl);
-                window.location.href = data.logoutUrl + '?service=' + encodeURI(data.redirectUrl);
+                window.location.href = data.logoutUrl;
             })
         ).subscribe();
     }