diff --git a/src/App.jsx b/src/App.jsx index 52e77a476ebc36be1391dd9b8a04d616d86ade90..a8c3e9f7ff4d8ede2d91e7546f7f37e63dd0c533 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -11,7 +11,7 @@ import { loadAnnouncements } from "actions/announcements"; import { loadConfig } from "actions/global-info"; import { loadPosts } from "actions/posts"; import { loadProgram } from "actions/program"; -import { loadMe } from "actions/users"; +import { loadMe, refreshAccessToken } from "actions/users"; import { initializeWSChannel } from "actions/ws"; import Footer from "components/Footer"; import Navbar from "components/Navbar"; @@ -39,7 +39,12 @@ if (process.env.REACT_APP_SENTRY_DSN) { const ReactHint = ReactHintFactory(React); -const onKeycloakEvent = (event) => { +const onKeycloakEvent = async (event) => { + if (event === "onTokenExpired") { + console.warn("[auth] access token expired, attempting refresh"); + refreshAccessToken(); + } + if (["onAuthRefreshSuccess", "onAuthSuccess"].includes(event)) { Sentry.setUser(keycloak.tokenParsed); @@ -154,6 +159,7 @@ const AuthenticatedApp = () => { initConfig={keycloakInitConfig} LoadingComponent={LoadingComponent} onEvent={onKeycloakEvent} + autoRefreshToken={false} > <Suspense fallback={LoadingComponent}> <ConfiguredApp /> diff --git a/src/actions/users.js b/src/actions/users.js index 3bb8fb4a05bdef364e7df4d5a1b1b7d088bd29de..c3a626698be9b0fde216194336a6317767dad1fd 100644 --- a/src/actions/users.js +++ b/src/actions/users.js @@ -1,7 +1,10 @@ +import * as Sentry from "@sentry/react"; import { createAsyncAction, errorResult, successResult } from "pullstate"; import { fetch } from "api"; -import { AuthStore } from "stores"; +import keycloak from "keycloak"; +import { AuthStore, PostStore } from "stores"; +import { updateWindowPosts } from "utils"; export const loadMe = createAsyncAction( /** @@ -89,3 +92,28 @@ export const inviteToJitsi = createAsyncAction( } } ); + +export const refreshAccessToken = async () => { + try { + await keycloak.updateToken(300); + console.info("[auth] access token refreshed"); + } catch (exc) { + console.warn( + "[auth] could not refresh the access token, refresh token possibly expired, logging out" + ); + + Sentry.setUser(null); + + AuthStore.update((state) => { + state.isAuthenticated = false; + state.user = null; + state.showJitsiInvitePopup = false; + state.jitsiPopupDimissed = false; + }); + + PostStore.update((state) => { + state.filters.showPendingProposals = false; + updateWindowPosts(state); + }); + } +}; diff --git a/src/index.js b/src/index.js index 63f13377424e58ef3ba12bee37c012fac2069cb8..7565c0e112c1d42a168d6dde095b924fde71d552 100644 --- a/src/index.js +++ b/src/index.js @@ -2,11 +2,21 @@ import React from "react"; import ReactDOM from "react-dom"; import ReactModal from "react-modal"; +import { refreshAccessToken } from "actions/users"; + import App from "./App"; import * as serviceWorker from "./serviceWorker"; const root = document.getElementById("root"); +function handleVisibilityChange() { + if (!document.hidden) { + refreshAccessToken(); + } +} + +document.addEventListener("visibilitychange", handleVisibilityChange, false); + ReactDOM.render( <React.StrictMode> <App />