Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 Revert "🐛 Fix session expiry when refresh tokens are disabled" #1615

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 5 additions & 34 deletions client/src/app/axios-config/apiInit.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,14 @@
import axios from "axios";
import keycloak from "@app/keycloak";

export const initInterceptors = () => {
export const initInterceptors = (getToken: () => Promise<string>) => {
axios.interceptors.request.use(
(config) => {
const token = keycloak.token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
async (config) => {
const token = await getToken();
if (token) config.headers["Authorization"] = "Bearer " + token;
return config;
},
(error) => {
return Promise.reject(error);
}
);

axios.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
if (error.response && error.response.status === 401) {
try {
const refreshed = await keycloak.updateToken(5);
if (refreshed) {
const retryConfig = {
...error.config,
headers: {
...error.config.headers,
Authorization: `Bearer ${keycloak.token}`,
},
};
return axios(retryConfig);
}
} catch (refreshError) {
keycloak.login();
}
}
return Promise.reject(error);
Promise.reject(error);
}
);
};
98 changes: 83 additions & 15 deletions client/src/app/components/KeycloakProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React, { Suspense } from "react";
import { ReactKeycloakProvider } from "@react-keycloak/web";
import { initInterceptors } from "@app/axios-config";
import { isAuthRequired } from "@app/Constants";
import i18n from "@app/i18n";
import keycloak from "@app/keycloak";
import { deleteCookie, getCookie, setCookie } from "@app/queries/cookies";
import { AppPlaceholder } from "./AppPlaceholder";
import { initInterceptors } from "@app/axios-config";
import { Flex, FlexItem, Spinner } from "@patternfly/react-core";
import { ReactKeycloakProvider } from "@react-keycloak/web";
import React, { Suspense } from "react";

interface IKeycloakProviderProps {
children: React.ReactNode;
Expand All @@ -11,17 +15,81 @@ interface IKeycloakProviderProps {
export const KeycloakProvider: React.FC<IKeycloakProviderProps> = ({
children,
}) => {
React.useEffect(() => {
initInterceptors();
}, []);
const checkAuthCookie = () => {
if (!getCookie("keycloak_cookie") && keycloak?.token) {
setCookie("keycloak_cookie", keycloak.token, 365);
}
};
if (isAuthRequired) {
return (
<>
<ReactKeycloakProvider
authClient={keycloak}
initOptions={{ onLoad: "login-required" }}
LoadingComponent={
<Flex
spaceItems={{ default: "spaceItemsSm" }}
alignItems={{ default: "alignItemsCenter" }}
flexWrap={{ default: "nowrap" }}
style={{
width: "100%",
height: "100%",
}}
>
<FlexItem
style={{
margin: "auto auto",
textAlign: "center",
}}
>
<Spinner>Loading...</Spinner>
</FlexItem>
</Flex>
}
isLoadingCheck={(keycloak) => {
if (keycloak.authenticated) {
initInterceptors(
() =>
new Promise<string>((resolve, reject) => {
if (keycloak.token) {
if (keycloak.refreshToken) {
keycloak
.updateToken(60)
.then(() => {
deleteCookie("keycloak_cookie");
checkAuthCookie();
return resolve(keycloak.token!);
})
.catch((err) => {
console.log("err", err);
return reject("Failed to refresh token");
});
} else return resolve(keycloak.token!);
} else {
keycloak.login();
reject("Not logged in");
}
})
);

const kcLocale = (keycloak.tokenParsed as any)["locale"];
if (kcLocale) {
i18n.changeLanguage(kcLocale);
}
}

return (
<ReactKeycloakProvider
authClient={keycloak}
initOptions={{ onLoad: "login-required" }}
LoadingComponent={<AppPlaceholder />}
>
<Suspense fallback={<AppPlaceholder />}>{children}</Suspense>
</ReactKeycloakProvider>
);
return !keycloak.authenticated;
}}
>
{children}
</ReactKeycloakProvider>
</>
);
} else {
return (
<>
<Suspense fallback={<AppPlaceholder />}>{children}</Suspense>
</>
);
}
};
5 changes: 3 additions & 2 deletions client/src/app/layout/HeaderApp/SSOMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ export const SSOMenu: React.FC = () => {
id="sso-actions-toggle"
onClick={() => onDropdownToggle(!isDropdownOpen)}
>
{(keycloak?.idTokenParsed as any)?.["preferred_username"] ??
"DefaultUsername"}
{(keycloak?.idTokenParsed as any)["preferred_username"]}
</MenuToggle>
)}
>
Expand All @@ -64,6 +63,8 @@ export const SSOMenu: React.FC = () => {
id="logout"
key="sso_logout"
onClick={() => {
// Clears selected persona from storage without updating it in React state so we don't re-render the persona selector while logging out.
// We have to clear it before logout because the redirect can happen before the logout promise resolves.
window.localStorage.removeItem(
LocalStorageKey.selectedPersona
);
Expand Down
Loading