diff --git a/apps/web/.env b/apps/web/.env
index 3748091227f84a56cbfe836fbb081e9635fc1a5c..f651adbd016aeac3956bde79d0f2c1de67081320 100644
--- a/apps/web/.env
+++ b/apps/web/.env
@@ -1,2 +1,2 @@
 VITE_BACKEND_URL=api.graphpolaris.com
-VITE_STAGING=local
\ No newline at end of file
+VITE_STAGING=local
diff --git a/apps/web/node.d.ts b/apps/web/node.d.ts
index 0156111480f412902209f239be01e460baa8192f..9c681853c7020e2fee31b6b4eb34490d72cdf5ac 100644
--- a/apps/web/node.d.ts
+++ b/apps/web/node.d.ts
@@ -2,5 +2,8 @@ interface ImportMeta {
     env: {
         VITE_BACKEND_URL: string;
         VITE_STAGING: string;
+        VITE_KEYCLOAK_URL: string;
+        VITE_KEYCLOAK_REALM: string;
+        VITE_KEYCLOAK_CLIENT: string;
     }
 }
\ No newline at end of file
diff --git a/apps/web/src/app/app.module.scss b/apps/web/src/app/app.module.scss
index 328ed5e2dc9feb139a8a9b695b717be949295c39..b04f78a7d2813bc96bf2cae6a6048793725ad4a5 100644
--- a/apps/web/src/app/app.module.scss
+++ b/apps/web/src/app/app.module.scss
@@ -10,7 +10,7 @@
     width: 100%;
     max-width: 33%;
     height: 100%;
-    max-height: 70%;
+    max-height: 100%;
   }
   .panel {
     display: flex;
diff --git a/apps/web/src/app/app.tsx b/apps/web/src/app/app.tsx
index 6972e3473f24dfd9bdb4186d81442e32f0dc31df..eb99a9a0803cb7402b9d4bfa895b54768559e58e 100644
--- a/apps/web/src/app/app.tsx
+++ b/apps/web/src/app/app.tsx
@@ -1,50 +1,42 @@
-import { useEffect, useRef, useState } from 'react';
-import GridLayout from 'react-grid-layout';
-import Panel from '../components/panels/panel';
-import { RawJSONVis } from '@graphpolaris/shared/lib/vis/rawjsonvis/rawjsonvis';
-import SemanticSubstrates from '@graphpolaris/shared/lib/vis/semanticsubstrates/semanticsubstrates';
-import { Schema } from '@graphpolaris/shared/lib/schema/panel';
-import {
-  Query2BackendQuery,
-  QueryBuilder,
-} from '@graphpolaris/shared/lib/querybuilder';
-import {
-  assignNewGraphQueryResult,
-  useAppDispatch,
-} from '@graphpolaris/shared/lib/data-access/store';
-import { Navbar } from '../components/navbar/navbar';
-import { VisualizationPanel } from './panels/Visualization';
 import {
   readInSchemaFromBackend,
-  useAuthorization,
+  useAuth,
   useAuthorizationCache,
   useDatabaseAPI,
   useQueryAPI,
   useQuerybuilderGraph,
-  useQuerybuilderGraphology,
   useQuerybuilderHash,
   useSchemaAPI,
-  useSessionCache,
+  useSessionCache
 } from '@graphpolaris/shared/lib/data-access';
-import LoginScreen from '../components/login/loginScreen';
 import { WebSocketHandler } from '@graphpolaris/shared/lib/data-access/socket';
 import Broker from '@graphpolaris/shared/lib/data-access/socket/broker';
-import { SchemaFromBackend } from '@graphpolaris/shared/lib/model/backend';
-import { domain } from '../environments/variables';
-import { QueryMultiGraphExport } from '@graphpolaris/shared/lib/querybuilder/graph/graphology/utils';
 import {
-  GraphQueryResultFromBackend,
-  resetGraphQueryResults,
-} from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
-import { clearQB } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
+  assignNewGraphQueryResult,
+  useAppDispatch,
+} from '@graphpolaris/shared/lib/data-access/store';
+import { GraphQueryResultFromBackend, resetGraphQueryResults } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
+import {
+  Query2BackendQuery,
+  QueryBuilder,
+} from '@graphpolaris/shared/lib/querybuilder';
+import { Schema } from '@graphpolaris/shared/lib/schema/panel';
+import { useEffect, useRef, useState } from 'react';
+import { Navbar } from '../components/navbar/navbar';
+import Panel from '../components/panels/panel';
+import { domain } from '../environments/variables';
+import { VisualizationPanel } from './panels/Visualization';
 import styles from './app.module.scss';
+import { logout } from '@graphpolaris/shared/lib/data-access/store/authSlice';
+import { SchemaFromBackend } from '@graphpolaris/shared/lib/schema';
 
 export interface App {
   styles: any;
 }
 
 export function App(props: App) {
-  const { AuthorizeFromCache, auth } = useAuthorization(domain);
+  const isLogin = useAuth();
+  const auth = useAuthorizationCache()
   const api = useDatabaseAPI(domain);
   const api_schema = useSchemaAPI(domain);
   const api_query = useQueryAPI(domain);
@@ -55,9 +47,13 @@ export function App(props: App) {
   const ws = useRef(new WebSocketHandler(domain));
   const [authCheck, setAuthCheck] = useState(false);
 
+  // for testing purposes
+  // useEffect(() => {
+  //   console.info('Authentification changed', auth)
+  // }, [auth]);
+
   useEffect(() => {
     // Default
-    AuthorizeFromCache();
     Broker.instance().subscribe(
       (data: SchemaFromBackend) => dispatch(readInSchemaFromBackend(data)),
       'schema_result'
@@ -77,7 +73,7 @@ export function App(props: App) {
 
   useEffect(() => {
     // New active database
-    if (session.currentDatabase) {
+    if (auth.accessToken && session.currentDatabase) {
       ws.current.useToken(auth.accessToken).connect(() => {
         api_schema.RequestSchema(session.currentDatabase);
       });
@@ -86,12 +82,14 @@ export function App(props: App) {
 
   useEffect(() => {
     // Newly (un)authorized
-    console.log(auth.authorized);
     if (auth.authorized) {
+      console.info("App is authorized; Getting Datatabases", isLogin);
       api.GetAllDatabases({ updateSessionCache: true });
       setAuthCheck(true);
+    } else {
+      dispatch(logout())
     }
-  }, [auth.authorized]);
+  }, [isLogin]);
 
   useEffect(() => {
     // New query
@@ -105,7 +103,6 @@ export function App(props: App) {
 
   return (
     <div className="h-screen w-screen">
-      {auth.authorized === false && <LoginScreen />}
       <div
         className={
           'flex h-screen w-screen overflow-hidden ' +
diff --git a/apps/web/src/components/login/loginScreen.tsx b/apps/web/src/components/login/loginScreen.tsx
deleted file mode 100644
index 82f2d7fbb27f3542f2c194dec9a511bd26eefded..0000000000000000000000000000000000000000
--- a/apps/web/src/components/login/loginScreen.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import { useAuthorizationCache } from '@graphpolaris/shared/lib/data-access';
-import { useAuthorization } from '@graphpolaris/shared/lib/data-access/authorization';
-import { domain } from '../../environments/variables';
-import styled from 'styled-components';
-import EmailIcon from '@mui/icons-material/Email';
-
-const Wrapper = styled.div`
-  font-family: Arial, serif;
-  position: absolute;
-  left: 0;
-  top: 0;
-  // Cover the screen
-  width: 100vw;
-  height: 100vh;
-
-  display: flex;
-  justify-content: center;
-  align-items: center;
-`;
-
-const Background = styled.div`
-  position: absolute;
-
-  width: 100%;
-  height: 100%;
-
-  z-index: 1;
-
-  // Blur
-  background: rgba(
-    0,
-    0,
-    0,
-    0.4
-  ); // Make sure this color has an opacity of less than 1
-  backdrop-filter: blur(8px); // This be the blur
-`;
-
-const Content = styled.div`
-  background-color: white;
-  box-shadow: 0 3px 10px rgb(0 0 0 / 0.2);
-  padding: 2em;
-  z-index: 2;
-  border-radius: 8px;
-
-  display: flex;
-  flex-direction: column;
-  gap: 1em;
-  align-items: center;
-  justify-content: center;
-
-  // Give children 0 padding and margin
-  * {
-    display: flex;
-    margin: 0;
-    padding: 0;
-
-    // Same width flexbox items
-    flex: 1 1 0;
-
-    max-height: 3em;
-
-    &:hover {
-      cursor: pointer;
-    }
-  }
-`;
-
-const LoginScreen = () => {
-  const { SetAccessToken } = useAuthorization(domain);
-
-  const openSignInWindow = (url: string) => {
-    window.location.assign(url);
-  };
-
-  return (
-    <Wrapper>
-      <Background></Background>
-      <Content>
-        <h1 className="pointer-events-none">Sign In</h1>
-        <img
-          onClick={() =>
-            openSignInWindow(
-              'https://api.graphpolaris.com/user/sign-in?provider=1&callback=https://local.graphpolaris.com:4200/'
-            )
-          }
-          src="assets/login-screen/google.png"
-          alt="sign up with google"
-        />
-        <img
-          onClick={() =>
-            openSignInWindow(
-              'https://api.graphpolaris.com/user/sign-in?provider=2&callback=https://local.graphpolaris.com:4200/'
-            )
-          }
-          src="assets/login-screen/github.png"
-          alt="sign up with github"
-        />
-        <button className='btn bg-gray-400 rounded-md p-1'>
-          <EmailIcon />
-        </button>
-        <p
-          onClick={() =>
-            openSignInWindow('https://api.graphpolaris.com/user/create_free/')
-          }
-        >
-          Demo
-        </p>
-      </Content>
-    </Wrapper>
-  );
-};
-
-export default LoginScreen;
diff --git a/apps/web/src/components/login/popup.tsx b/apps/web/src/components/login/popup.tsx
deleted file mode 100644
index 73231dc6da73e40763eeed26cd9ae9e2099858c8..0000000000000000000000000000000000000000
--- a/apps/web/src/components/login/popup.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-const LoginPopupComponent = () => {
-  if (window.opener) {
-    // Get the access token from the query params
-    const urlParams = new URLSearchParams(window.location.search);
-    const accessToken = urlParams.get('access_token');
-
-    // Send the access token to the parent window
-    const c_event = new CustomEvent('auth_message', {
-      detail: { token: accessToken, origin: window.location.hostname },
-    });
-    window.opener.dispatchEvent(c_event);
-    // window.opener.postMessage(accessToken, '*');
-
-    // Close this window
-    window.close();
-  }
-
-  return <h1>Loading...</h1>;
-};
-
-export default LoginPopupComponent;
diff --git a/apps/web/src/components/navbar/AddDatabaseForm/index.tsx b/apps/web/src/components/navbar/AddDatabaseForm/index.tsx
index acef980f97760382ce522bf43ea730f54c7e9d01..c13df46c392bf8507cd4997215951d9740762db9 100644
--- a/apps/web/src/components/navbar/AddDatabaseForm/index.tsx
+++ b/apps/web/src/components/navbar/AddDatabaseForm/index.tsx
@@ -40,14 +40,21 @@ export interface AddDatabaseFormState extends AddDatabaseRequest {
 /** AddDatabaseForm is the View implementation for the connect screen that will be rendered. */
 export default function AddDatabaseForm(props: AddDatabaseFormProps) {
   const [state, setState] = useState<AddDatabaseFormState>({
-    username: 'root',
-    password: 'DikkeDraak',
-    url: 'https://datastrophe.science.uu.nl/',
-    port: 8529,
-    name: 'Tweede Kamer Dataset',
-    internal_database_name: 'TweedeKamer',
-    // styles: props.styles, // FIXME
-    type: DatabaseType.ArangoDB,
+    // username: 'root',
+    // password: 'DikkeDraak',
+    // url: 'https://datastrophe.science.uu.nl/',
+    // port: 8529,
+    // name: 'Tweede Kamer Dataset',
+    // internal_database_name: 'TweedeKamer',
+    // type: DatabaseType.ArangoDB,
+
+    username: 'neo4j',
+    password: 'oL3nNlebrx4le2A0zxaFVqAo3HAvodHxwEiI_7_2JxI',
+    url: '635176c8.databases.neo4j.io',
+    port: 7687,
+    name: 'neo4j',
+    internal_database_name: 'neo4j',
+    type: DatabaseType.Neo4j,
   });
   const [portValidation, setPortValidation] = useState<string>('valid');
 
@@ -59,6 +66,15 @@ export default function AddDatabaseForm(props: AddDatabaseFormProps) {
     }
   }, [state.port]);
 
+  useEffect(() => {
+    if (!state) return;
+    if (state.type === DatabaseType.ArangoDB && state.port === 7687) {
+      setState({ ...state, port: 8529 });
+    } else if (state.type === DatabaseType.Neo4j && state.port === 8529) {
+      setState({ ...state, port: 7687 });
+    }
+  }, [state.type]);
+
   /**
    * Validates if the port value is numerical. Only then will the state be updated.
    * @param port The new port value.
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
index 588f0faf3e145525e8ca14311de2ffe319c92e47..483b0d21b5718072f82dc621247151aa686e74e6 100644
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -8,7 +8,6 @@ import { Provider } from 'react-redux';
 import { store } from '@graphpolaris/shared/lib/data-access/store';
 import { GraphPolarisThemeProvider } from '@graphpolaris/shared/lib/data-access/theme';
 import App from './app/app';
-import LoginPopupComponent from './components/login/popup';
 import { CssBaseline } from '@mui/material';
 import { createRoot } from 'react-dom/client';
 import './styles.css';
@@ -25,8 +24,6 @@ if (domNode) {
         <CssBaseline />
         <Router>
           <Routes>
-            {/* Route to auth component in popup */}
-            <Route path="/auth" element={<LoginPopupComponent />}></Route>
             {/* App */}
             <Route path="/" element={<App />}></Route>
           </Routes>
diff --git a/libs/shared/.env b/libs/shared/.env
new file mode 100644
index 0000000000000000000000000000000000000000..25874d424ea58a84f5965f652718f6e2b5a4a400
--- /dev/null
+++ b/libs/shared/.env
@@ -0,0 +1,3 @@
+VITE_KEYCLOAK_URL=https://login.graphpolaris.com/  
+VITE_KEYCLOAK_REALM=graphpolaris
+VITE_KEYCLOAK_CLIENT=web
\ No newline at end of file
diff --git a/libs/shared/lib/data-access/api/database.ts b/libs/shared/lib/data-access/api/database.ts
index 5764cfe0f92194e1b7714ef179a0f6454afbce8d..0904869942c4e9443fabf18467e685b8ccecb4ef 100644
--- a/libs/shared/lib/data-access/api/database.ts
+++ b/libs/shared/lib/data-access/api/database.ts
@@ -69,7 +69,7 @@ export const useDatabaseAPI = (domain: string) => {
 
   async function GetAllDatabases(options: GetDatabasesOptions = {}): Promise<Array<string>> {
     const { updateSessionCache: updateDatabaseCache = true } = options;
-    console.log(accessToken);
+    // console.log(accessToken);
     const response = await fetch(`https://${domain}/user/database`, {
       method: 'GET',
       credentials: 'same-origin',
@@ -116,4 +116,4 @@ export const useDatabaseAPI = (domain: string) => {
   }
 
   return { DatabaseType, AddDatabase, GetAllDatabases, DeleteDatabase }
-};
\ No newline at end of file
+};
diff --git a/libs/shared/lib/data-access/authorization/authorizationHook.tsx b/libs/shared/lib/data-access/authorization/authorizationHook.tsx
deleted file mode 100644
index d607d375ab61df6c457be2ec78a8e8b74072fe1a..0000000000000000000000000000000000000000
--- a/libs/shared/lib/data-access/authorization/authorizationHook.tsx
+++ /dev/null
@@ -1,189 +0,0 @@
-import { useEffect, useState } from 'react';
-import { useAppDispatch, useAuthorizationCache } from '../store';
-import { dispatch } from 'd3';
-import { authorized, unauthorized, updateAccessToken } from '../store/authSlice';
-
-/**
- * getNewAccessToken gets a new access token using the refresh-token cookie
- * @returns an authResponse containing details
- */
-async function getNewAccessToken(
-  domain: string,
-  accessToken: string
-): Promise<authResponse> {
-  // If we have an access token already, append it to the url as a query param to keep sessionID the same
-  let url = `https://${domain}/auth/refresh`;
-  if (accessToken != '') {
-    url += '?access_token=' + accessToken;
-  }
-
-  try {
-    const response = await fetch(url, {
-      method: 'GET',
-      credentials: 'include',
-    });
-
-    if (!response.ok) {
-      // User is not authorized
-      const text = await response.text();
-      console.error('User UNAUTHORIZED', text);
-
-      return { success: false };
-      // throw Error(response.statusText);
-    }
-
-    const json = await response.json();
-    return {
-      success: true,
-      accessToken: json.accessToken,
-      userID: json.userID,
-      sessionID: json.sessionID,
-    };
-  } catch (error) {
-    console.error('Error authorizing user', error);
-    return { success: false };
-  }
-}
-
-type authResponse = {
-  success: boolean;
-  accessToken?: string;
-  userID?: string;
-  sessionID?: string;
-};
-
-export type useIsAuthorizedState = {
-  userID?: string;
-  sessionID?: string;
-  accessToken: string;
-  authorized?: boolean;
-};
-
-export function useAuthorization(domain: string) {
-  const dispatch = useAppDispatch();
-  const auth = useAuthorizationCache();
-
-  /**
-   * refreshTokens refreshes tokens
-   */
-  async function refreshTokens() {
-    console.log('refreshing tokens');
-    // Get a new access + refresh token pair
-    const authResponse = await getNewAccessToken(domain, auth.accessToken);
-
-    if (authResponse.success) {
-      // Set the new access token
-      dispatch(updateAccessToken(authResponse.accessToken ?? ''));
-
-      if (auth.accessToken !== '') {
-        // Initialize the new refresh token
-        initializeRefreshToken();
-      }
-    }
-  }
-
-  // /**
-  //  * initializeRefreshToken attempts to initialize a refresh token
-  //  */
-  // async function refreshRefreshToken() {
-  //   fetch(
-  //     'https://${domain}/auth/refresh?access_token=' +
-  //       state.accessToken,
-  //     {
-  //       method: 'GET',
-  //       credentials: 'include',
-  //     }
-  //   )
-  //     .then((response) => {
-  //       if (!response.ok) {
-  //         throw Error(response.statusText);
-  //       }
-  //     })
-  //     .catch((error) => {
-  //       console.error(error);
-  //     });
-  // }
-
-  /**
-   * initializeRefreshToken attempts to initialize a refresh token
-   */
-  async function initializeRefreshToken() {
-    fetch(`https://${domain}/auth/refresh`, {
-      method: 'POST',
-      credentials: 'include',
-    })
-      .then((response) => {
-        if (!response.ok) {
-          console.error(response.statusText);
-          // throw Error(response.statusText);
-        }
-      })
-      .catch((error) => {
-        console.error(error);
-      });
-  }
-
-  // MARK: Setters
-  /**
-   * SetAccessToken sets the current access token (should only be called by the sign-in component)
-   * @param accessToken
-   */
-  async function SetAccessToken(accessToken: string) {
-    dispatch(updateAccessToken(accessToken));
-    console.log('set access token', auth.accessToken);
-
-    const result = await AuthorizeFromCache();
-    if (result) {
-      // Activate the refresh token TODO
-      initializeRefreshToken();
-
-      // Start the automatic refreshing every 10 minutes
-      setInterval(() => {
-        refreshTokens();
-      }, 10 * 60 * 1000);
-    } else {
-      console.error(
-        'Failed Logging in due to refresh token initialization',
-        result
-      );
-      // throw Error('Failed Logging in');
-    }
-  }
-
-  /**
-   * Authorize attempts to authorize using a refresh-token set as a cookie. If the user has been inactive for more than 7 days this cookie will be gone.
-   * @returns true is authorization was successful, else returns false
-   */
-  async function AuthorizeFromCache(): Promise<boolean> {
-    // Attempt to log in with a refresh-token
-    const authResponse = await getNewAccessToken(domain, auth.accessToken);
-
-    // If the request was a success, we have an accessToken, userID and sessionID
-    if (authResponse.success) {
-      console.log('SUCCESS authorize');
-
-      console.log(auth);
-      // Store them
-      await dispatch(
-        authorized({
-          userID: authResponse.userID ?? '',
-          sessionID: authResponse.sessionID ?? '',
-          accessToken: authResponse.accessToken ?? '',
-          authorized: true,
-        })
-      );
-    } else {
-      await dispatch(
-        unauthorized()
-      );
-    }
-
-    return authResponse.success;
-  }
-
-  return {
-    AuthorizeFromCache,
-    SetAccessToken,
-    auth,
-  };
-}
diff --git a/libs/shared/lib/data-access/authorization/index.ts b/libs/shared/lib/data-access/authorization/index.ts
index 521daf5096bc7c9567fca3db52dea7cd6db6a00b..d9ae7204eb493add99673b64e2249652d3adbcd3 100644
--- a/libs/shared/lib/data-access/authorization/index.ts
+++ b/libs/shared/lib/data-access/authorization/index.ts
@@ -1 +1 @@
-export * from './authorizationHook';
\ No newline at end of file
+export * from './useAuth';
diff --git a/libs/shared/lib/data-access/authorization/useAuth.jsx b/libs/shared/lib/data-access/authorization/useAuth.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..644abac87fcf2c7637ecfcf35e27b9b86a69e904
--- /dev/null
+++ b/libs/shared/lib/data-access/authorization/useAuth.jsx
@@ -0,0 +1,71 @@
+import Keycloak from 'keycloak-js';
+import { useEffect, useRef, useState } from 'react';
+import { useAppDispatch } from '../store';
+
+import { authorized } from '../store/authSlice';
+
+export const useAuth = () => {
+  const keycloak = new Keycloak({
+    // url: import.meta.env.VITE_KEYCLOAK_URL,
+    // realm: import.meta.env.VITE_KEYCLOAK_REALM,
+    // clientId: import.meta.env.VITE_KEYCLOAK_CLIENT,
+    //TODO: remove this hardcode
+    url: 'https://keycloak.graphpolaris.com',
+    realm: 'graphpolaris',
+    clientId: 'web',
+  });
+
+  const isRun = useRef(false);
+  const [isLogin, setLogin] = useState(false);
+  const dispatch = useAppDispatch();
+
+  useEffect(() => {
+    if (isRun.current) return;
+
+    isRun.current = true;
+    keycloak
+      .init({
+        onLoad: 'login-required',
+        enableLogging: false,
+        checkLoginIframe: false,
+      })
+      .then(async (isAuthenticated) => {
+        // console.log("useAuth useEffect", isAuthenticated, keycloak.idTokenParsed);
+        setLogin(isAuthenticated);
+
+        // just for example here:
+        // const profile = await getUserProfile();
+        // console.log("useAuth useEffect profile", profile);
+
+        await dispatch(
+          authorized({
+            // Info from https://www.keycloak.org/docs/latest/securing_apps/
+            userID: keycloak.idTokenParsed.preferred_username ?? '',
+            sessionID: keycloak.idTokenParsed.sid ?? '',
+            accessToken: keycloak.token ?? '',
+            authorized: true,
+          })
+        );
+      })
+      .catch((err) => {
+        console.error('useAuth err', err);
+        throw err;
+      });
+  }, []);
+
+  const getUserProfile = async () => {
+    return keycloak
+      .loadUserProfile()
+      .then(function (profile) {
+        return profile;
+        // console.info("user info", JSON.stringify(profile, null, "  "))
+      })
+      .catch(function () {
+        alert('Failed to load user profile');
+      });
+  };
+
+  return isLogin;
+};
+
+// export useAuth;
diff --git a/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx b/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx
index 7645f8c008b6742189438fa22986d30cb5d2d3c4..55669800e32c4663b87e19005ada5bc2cf1bc1ae 100644
--- a/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx
+++ b/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx
@@ -34,7 +34,7 @@ export class WebSocketHandler implements BackendMessageReceiver {
     if (this.webSocket) this.close();
 
     this.webSocket = new WebSocket(
-      this.url + (!!this.token ? `?jwt=${this.token}` : '')
+      this.url + (!!this.token ? `?jwt=${encodeURIComponent(this.token)}` : '')
     );
     this.webSocket.onopen = () => onOpen();
     this.webSocket.onmessage = this.onWebSocketMessage;
diff --git a/libs/shared/lib/data-access/store/authSlice.ts b/libs/shared/lib/data-access/store/authSlice.ts
index 19dbb398142df1a67ce1638ee3b614a9276ab5fa..b088f1dcf1dd6ae23dd97bfec76ed0532e8ad18f 100644
--- a/libs/shared/lib/data-access/store/authSlice.ts
+++ b/libs/shared/lib/data-access/store/authSlice.ts
@@ -7,7 +7,9 @@ import { useIsAuthorizedState } from '../authorization';
 // Define the initial state using that type
 export const initialState: useIsAuthorizedState = {
   authorized: undefined,
-  accessToken: '',
+  accessToken: undefined,
+  sessionID: undefined,
+  userID: undefined,
 };
 
 export const authSlice = createSlice({
@@ -24,6 +26,12 @@ export const authSlice = createSlice({
       state.sessionID = action.payload.sessionID;
       state.userID = action.payload.userID;
     },
+    logout(state) {
+      state.authorized = undefined;
+      state.accessToken = undefined;
+      state.sessionID = undefined;
+      state.userID = undefined;
+    },
     unauthorized(state) {
       state.authorized = false;
     }
@@ -31,7 +39,7 @@ export const authSlice = createSlice({
 });
 
 export const {
-  updateAccessToken, authorized, unauthorized
+  updateAccessToken, authorized, unauthorized, logout
 } = authSlice.actions;
 
 // Other code such as selectors can use the imported `RootState` type
diff --git a/libs/shared/lib/schema/panel/schema.module.scss b/libs/shared/lib/schema/panel/schema.module.scss
index aeedac18dc5ce359147965ce1b4fd4b9036a5be9..687360fdff5cafcff20f66cacb10c2f03f8d2690 100644
--- a/libs/shared/lib/schema/panel/schema.module.scss
+++ b/libs/shared/lib/schema/panel/schema.module.scss
@@ -15,6 +15,7 @@
 
 .schemaPanel {
   width: 100%;
+  height: 100%;
   // display: 'flex';
   // flex-direction: 'column';
   // justify-content: 'center';
diff --git a/libs/shared/lib/schema/panel/schema.tsx b/libs/shared/lib/schema/panel/schema.tsx
index 2787b279fc924b0e52d42dd024cd10f0837df276..de9362d13f6e20c90eaa202b1e1976beb06b0f19 100644
--- a/libs/shared/lib/schema/panel/schema.tsx
+++ b/libs/shared/lib/schema/panel/schema.tsx
@@ -96,8 +96,8 @@ export const Schema = (props: Props) => {
   //   console.log('dbSchema', schemaGraphology, schemaGraphology.order);
   // }, [schemaGraphology]);
 
-  const toggleNodeQualityPopup = (id: string) => {};
-  const toggleAttributeAnalyticsPopupMenu = (id: string) => {};
+  const toggleNodeQualityPopup = (id: string) => { };
+  const toggleAttributeAnalyticsPopupMenu = (id: string) => { };
 
   function updateLayout() {
     const layoutFactory = new LayoutFactory();
@@ -182,21 +182,39 @@ export const Schema = (props: Props) => {
     // );
   }, [schemaGraph, schemaLayout]);
 
-  const graphStyles = { width: '100%', height: '500px' };
-
   // console.log(nodes, edges);
 
   return (
-    <div
-      style={{
-        width: '100%',
-        height: '100%',
-      }}
-    >
+    <div className={styles.schemaPanel} >
+      {firstUserConnection && (
+        <Card
+          variant="outlined"
+          sx={{
+            width: '20rem',
+            marginTop: 3,
+            zIndex: 9,
+            backgroundColor: '#ffffff',
+            position: 'absolute',
+          }}
+        >
+          <CardContent>
+            <Typography sx={{ fontSize: 20 }} color="text.secondary">
+              Press "space" while you move the schema
+            </Typography>
+            <LinearProgress
+              sx={{
+                color: (theme) =>
+                  theme.palette.grey[
+                  theme.palette.mode === 'light' ? 200 : 800
+                  ],
+              }}
+            />
+          </CardContent>
+        </Card>
+      )}
       {nodes.length === 0 && <p>DEBUG: No Elements</p>}
       <ReactFlowProvider>
         <ReactFlow
-          className={styles.schemaPanel}
           onlyRenderVisibleElements={false}
           nodesDraggable={false}
           nodeTypes={nodeTypes}
@@ -206,39 +224,10 @@ export const Schema = (props: Props) => {
           onEdgesChange={onEdgeChanged}
           nodes={nodes}
           edges={edges}
-          style={graphStyles}
           onInit={onInit}
           panOnDrag={false}
           attributionPosition="top-right"
         >
-          {firstUserConnection && (
-            <Card
-              variant="outlined"
-              sx={{
-                minWidth: 275,
-                marginTop: 3,
-                marginRight: 10,
-                zIndex: 9,
-                backgroundColor: '#ffffff',
-                position: 'inherit',
-              }}
-            >
-              <CardContent>
-                <Typography sx={{ fontSize: 20 }} color="text.secondary">
-                  Press "space" while you move the schema
-                </Typography>
-                <LinearProgress
-                  sx={{
-                    color: (theme) =>
-                      theme.palette.grey[
-                        theme.palette.mode === 'light' ? 200 : 800
-                      ],
-                  }}
-                />
-              </CardContent>
-            </Card>
-          )}
-
           <Controls
             showInteractive={false}
             showZoom={false}
diff --git a/libs/shared/package.json b/libs/shared/package.json
index febc1b7a286832820c365fe18dbee69ef6c5b1fe..7854a1b6c4d581f85554c07b7d00e4bfbf53be96 100644
--- a/libs/shared/package.json
+++ b/libs/shared/package.json
@@ -43,6 +43,7 @@
     "graphology-types": "^0.24.7",
     "immer": "^10.0.2",
     "jspdf": "^2.5.1",
+    "keycloak-js": "^21.1.1",
     "pixi.js": "^7.1.4",
     "react-cookie": "^4.1.1",
     "react-grid-layout": "^1.3.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b9a9b42880da5de2a4f689f5e04e0cd35dc5e11a..1ffca810838bf8a300fb78a95a3bd4a35fc8a777 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -247,6 +247,9 @@ importers:
       jspdf:
         specifier: ^2.5.1
         version: 2.5.1
+      keycloak-js:
+        specifier: ^21.1.1
+        version: 21.1.1
       pixi.js:
         specifier: ^7.1.4
         version: 7.2.1(@pixi/utils@7.2.1)
@@ -7494,7 +7497,6 @@ packages:
 
   /base64-js@1.5.1:
     resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
-    dev: true
 
   /better-opn@2.1.1:
     resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==}
@@ -11000,6 +11002,10 @@ packages:
     resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==}
     dev: true
 
+  /js-sha256@0.9.0:
+    resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==}
+    dev: false
+
   /js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
@@ -11175,6 +11181,13 @@ packages:
     resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==}
     dev: false
 
+  /keycloak-js@21.1.1:
+    resolution: {integrity: sha512-Viyhf0SOpu2jM/A33vpigSCFLo8l4yg8lqzaGyxXoZ3nGO9lo68B2LwJBDtgpzqDUh8DK//yCOzdWuR2CT4keA==}
+    dependencies:
+      base64-js: 1.5.1
+      js-sha256: 0.9.0
+    dev: false
+
   /kind-of@6.0.3:
     resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
     engines: {node: '>=0.10.0'}