diff --git a/.env.development b/.env.development
index 544f6c74782f269b73faa0ddce97c1a256e0c9d5..4cb25fde8509fce62e08d1e175a641a72982296b 100644
--- a/.env.development
+++ b/.env.development
@@ -1 +1,2 @@
-VUE_APP_API="http://localhost:8080"
\ No newline at end of file
+VUE_APP_API="http://localhost:8080"
+VUE_APP_KEYCLOAK_URL="https://catalogue-keycloak-dev.k8s.medina.esilab.org/auth"
\ No newline at end of file
diff --git a/.env.production b/.env.production
index 58fe7e1d7ca02bb6eb4317b4fd58c47e1acaf3bb..9cc681bc0fed4661f3d749ea7e1ab162608bdc95 100644
--- a/.env.production
+++ b/.env.production
@@ -1 +1,2 @@
 VUE_APP_API="<<CCE_API_URL>>"
+VUE_APP_KEYCLOAK_URL="<<KEYCLOAK_URL>>"
diff --git a/entrypoint.sh b/entrypoint.sh
index 7c3eb90e209ec4596bef384b6141e31064c3d40a..d884d569c44a625dc60c5a572a035d24b86b4803 100644
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -1,5 +1,6 @@
 URL="${CCE_API_URL:-https://cce-api-dev.k8s.medina.esilab.org}"
 
 sed -i "s|<<CCE_API_URL>>|${CCE_API_URL}|g" /usr/share/nginx/html/js/app.*.js
+sed -i "s|<<KEYCLOAK_URL>>|${KEYCLOAK_URL}|g" /usr/share/nginx/html/js/app.*.js
 
 nginx -g 'daemon off;'
diff --git a/package.json b/package.json
index f915868b71f40d0003ab62c9222867cc143fec6d..07be703a6994d4495dea98f0235e8705f551a89e 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,8 @@
     "vue": "^3.2.47",
     "vue-axios": "^3.5.2",
     "vue-router": "^4.1.6",
-    "vuex": "^4.1.0"
+    "vuex": "^4.1.0",
+    "keycloak-js": "^21.0.2"
   },
   "devDependencies": {
     "@babel/eslint-parser": "^7.21.3",
diff --git a/src/main.js b/src/main.js
index 44dab70dc31e5fbedf11f0fc9b660f958f73588b..82fcb860737d8f3d850098902c393e4fd1629729 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,21 +1,55 @@
-import { createApp } from "vue";
+import {createApp} from "vue";
 import App from "./App.vue";
 import router from "./router";
 import store from "@/store";
 import axios from "axios";
 import VueAxios from "vue-axios";
+import Keycloak from "keycloak-js";
 
 import BootstrapVueNext from "bootstrap-vue-next";
 import "bootstrap/dist/css/bootstrap.css";
 import "bootstrap-vue-next/dist/bootstrap-vue-next.css";
 
-import { dom } from "@fortawesome/fontawesome-svg-core";
+import {dom} from "@fortawesome/fontawesome-svg-core";
 dom.watch();
 import "@fortawesome/fontawesome-free/css/all.css";
 
-const app = createApp(App);
-app.use(router);
-app.use(store);
-app.use(VueAxios, axios);
-app.use(BootstrapVueNext);
-app.mount("#app");
+let initOptions = {
+    url: process.env.VUE_APP_KEYCLOAK_URL,
+    realm: 'medina',
+    clientId: 'cce-frontend',
+    onLoad: 'login-required'
+}
+
+let keycloak = new Keycloak(initOptions);
+
+keycloak.init({onLoad: initOptions.onLoad}).then((auth) => {
+    if (!auth) {
+        window.location.reload();
+    } else {
+        axios.defaults.headers.common = {
+            'Authorization': 'Bearer ' + keycloak.token
+        };
+
+        const app = createApp(App);
+        app.use(router);
+        app.use(store);
+        app.use(VueAxios, axios);
+        app.use(BootstrapVueNext);
+        app.mount("#app");
+    }
+
+    setInterval(() => {
+        keycloak.updateToken(300).then((refreshed) => {
+            if (!refreshed) {
+                console.warn('Token not refreshed, valid for '
+                    + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');
+            }
+        }).catch(() => {
+            console.error('Failed to refresh token')
+        });
+    }, 300 * 1000)
+
+}).catch(() => {
+    console.error("Keycloak authentication failed");
+});
diff --git a/src/services/ApiService.js b/src/services/ApiService.js
index bfad5be9d6fe12bde8c88111bd02defb7aa7d8ac..6c14148732c695afcccb463094b81f9c29797b82 100644
--- a/src/services/ApiService.js
+++ b/src/services/ApiService.js
@@ -1,13 +1,17 @@
-import api from "@/client/client";
+import axios from "axios";
+
+const headers = {
+    "Content-Type": "application/json"
+};
 
 export const ApiService = {
-  getToeList() {
-    return api.get("/toeList");
-  },
-  getToeHistory(toeId) {
-    return api.get("/toes/" + toeId + "/listHistory");
-  },
-  getTreeByStateId(stateId) {
-    return api.get("/history/" + stateId);
-  },
+    getToeList() {
+        return axios.get(process.env.VUE_APP_API + "/toeList", {headers});
+    },
+    getToeHistory(toeId) {
+        return axios.get(process.env.VUE_APP_API + "/toes/" + toeId + "/listHistory", {headers});
+    },
+    getTreeByStateId(stateId) {
+        return axios.get(process.env.VUE_APP_API + "/history/" + stateId, {headers});
+    },
 };