From 3dab3af720a00e5c88a3cab607ecf910435a80fa Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Thu, 11 Apr 2024 12:23:16 +0200 Subject: [PATCH 01/14] build - update package --- .env | 12 +++++------- package.json | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.env b/.env index e7f70a2..2692e95 100644 --- a/.env +++ b/.env @@ -1,7 +1,5 @@ -VITE_API_ENDPOINT=https://api-pilotage-enquetes.developpement.insee.fr -VITE_AUTH_TYPE=oidc -VITE_OIDC_CLIENT_ID=coleman-pilotage -VITE_OIDC_ISSUER=https://auth.insee.test/auth/realms/questionnaire-particuliers -VITE_IDENTITY_PROVIDER=insee-ssp -VITE_ADMIN_LDAP_ROLE=administrateur_Platine -VITE_USER_LDAP_ROLE=utilisateur_Platine \ No newline at end of file +VITE_API_ENDPOINT=http://localhost:8000 +VITE_AUTH_TYPE=anonymous +VITE_OIDC_CLIENT_ID= +VITE_OIDC_ISSUER=https://localhost:8000 +VITE_IDENTITY_PROVIDER= \ No newline at end of file diff --git a/package.json b/package.json index 54dedf0..ebf507b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "platine-management", "private": true, - "version": "1.0.15", + "version": "1.0.16", "type": "module", "scripts": { "dev": "vite", From fe7bf781f814c1482bc8e77c2f30dbffbcf967d0 Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Thu, 11 Apr 2024 12:29:17 +0200 Subject: [PATCH 02/14] chore - add env vars roles ldap --- .env | 4 +++- src/vite-env.d.ts | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.env b/.env index 2692e95..3b7553c 100644 --- a/.env +++ b/.env @@ -2,4 +2,6 @@ VITE_API_ENDPOINT=http://localhost:8000 VITE_AUTH_TYPE=anonymous VITE_OIDC_CLIENT_ID= VITE_OIDC_ISSUER=https://localhost:8000 -VITE_IDENTITY_PROVIDER= \ No newline at end of file +VITE_IDENTITY_PROVIDER= +VITE_ADMIN_LDAP_ROLE= +VITE_USER_LDAP_ROLE= \ No newline at end of file diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 4c741ad..f230803 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -5,6 +5,8 @@ interface ImportMetaEnv { readonly VITE_OIDC_CLIENT_ID: string; readonly VITE_OIDC_ISSUER: string; readonly VITE_IDENTITY_PROVIDER: string; + readonly VITE_ADMIN_LDAP_ROLE: string; + readonly VITE_USER_LDAP_ROLE: string; } interface ImportMeta { From 4c01f38568a7c8c96cf86f5088ae9d9d4750fbfd Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Thu, 11 Apr 2024 12:35:29 +0200 Subject: [PATCH 03/14] chore - add env vars roles ldap --- src/hooks/usePermissions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts index e6a5059..c08b594 100644 --- a/src/hooks/usePermissions.ts +++ b/src/hooks/usePermissions.ts @@ -4,7 +4,7 @@ type User = ReturnType; type PermissionRequirement = string[] | ((user: User) => boolean); const permissions = { - ACCESS_SITE: ["admin", "user"], + ACCESS_SITE: [import.meta.env.VITE_ADMIN_LDAP_ROLE, import.meta.env.VITE_USER_LDAP_ROLE], EDIT_PAGE: ["admin", "user"], READ_PAGE: ["user"], DELETE_SITE: (user: User) => user.preferred_username === "admin", From 52b85967d06215ef23e8e557a827e8231820388b Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 08:14:48 +0200 Subject: [PATCH 04/14] fix - finalize issue --- .env | 4 ++-- src/App.tsx | 8 ++++---- src/hooks/usePermissions.ts | 3 ++- src/pages/UnauthorizedPage.tsx | 17 +++++++++++++---- src/routes.tsx | 13 +++++++++++++ src/ui/Header.tsx | 10 +++++++--- 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/.env b/.env index 3b7553c..6789606 100644 --- a/.env +++ b/.env @@ -3,5 +3,5 @@ VITE_AUTH_TYPE=anonymous VITE_OIDC_CLIENT_ID= VITE_OIDC_ISSUER=https://localhost:8000 VITE_IDENTITY_PROVIDER= -VITE_ADMIN_LDAP_ROLE= -VITE_USER_LDAP_ROLE= \ No newline at end of file +VITE_ADMIN_LDAP_ROLE=admin +VITE_USER_LDAP_ROLE=user diff --git a/src/App.tsx b/src/App.tsx index 2676973..a24c616 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,13 +1,13 @@ import { CircularProgress } from "@mui/material"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; -import { routes } from "./routes"; +import { routes, unauthorizedRoutes } from "./routes"; import { useIsAuthenticated } from "./hooks/useAuth"; import { useHasPermission } from "./hooks/usePermissions"; import "./App.css"; import { Row } from "./ui/Row"; -import { UnauthorizedPage } from "./pages/UnauthorizedPage"; const router = createBrowserRouter(routes); +const unauthorizedRouter = createBrowserRouter(unauthorizedRoutes); export function App() { const { isAuthenticated } = useIsAuthenticated(); @@ -24,11 +24,11 @@ export function App() { } function AuthenticatedApp() { - const canAccessSite = useHasPermission("ACCESS_SITE"); + const canAccessSite = useHasPermission("ACCESS_APP"); if (!canAccessSite) { // TODO : Mettre un composant Unauthorized - return ; + return ; } return ; diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts index c08b594..e556f5a 100644 --- a/src/hooks/usePermissions.ts +++ b/src/hooks/usePermissions.ts @@ -4,7 +4,8 @@ type User = ReturnType; type PermissionRequirement = string[] | ((user: User) => boolean); const permissions = { - ACCESS_SITE: [import.meta.env.VITE_ADMIN_LDAP_ROLE, import.meta.env.VITE_USER_LDAP_ROLE], + ACCESS_APP: [import.meta.env.VITE_ADMIN_LDAP_ROLE, import.meta.env.VITE_USER_LDAP_ROLE], + ACCESS_SETTINGS: [import.meta.env.VITE_ADMIN_LDAP_ROLE], EDIT_PAGE: ["admin", "user"], READ_PAGE: ["user"], DELETE_SITE: (user: User) => user.preferred_username === "admin", diff --git a/src/pages/UnauthorizedPage.tsx b/src/pages/UnauthorizedPage.tsx index 50fdf52..fdce885 100644 --- a/src/pages/UnauthorizedPage.tsx +++ b/src/pages/UnauthorizedPage.tsx @@ -1,4 +1,5 @@ -import { Stack, Typography } from "@mui/material"; +import { Box, Stack, Typography } from "@mui/material"; +import { Row } from "../ui/Row"; export function UnauthorizedPage() { return ( @@ -13,9 +14,17 @@ export function UnauthorizedPage() { minHeight={500} height="calc(100vh - 230px)" > - - Vous n'avez pas les droits nécessaires pour accéder à Platine Gestion - + + + {"Vous n'avez pas les droits nécessaires pour accéder à "} + + + + Platine + + Gestion + + ); diff --git a/src/routes.tsx b/src/routes.tsx index deae304..8f40372 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -11,6 +11,7 @@ import { SearchSurveys } from "./pages/Search/SearchSurveys.tsx"; import { SearchSurveyUnits } from "./pages/Search/SearchSurveyUnits.tsx"; import { SurveyUnitPage } from "./pages/SurveyUnitPage.tsx"; import { CreateContactPage } from "./pages/CreateContactPage.tsx"; +import { UnauthorizedPage } from "./pages/UnauthorizedPage.tsx"; export const routes: RouteObject[] = [ { @@ -41,3 +42,15 @@ export const routes: RouteObject[] = [ ], }, ]; + +export const unauthorizedRoutes: RouteObject[] = [ + { + path: "/*", + element: ( + + + + ), + errorElement: , + }, +]; diff --git a/src/ui/Header.tsx b/src/ui/Header.tsx index ace24c5..08677f6 100644 --- a/src/ui/Header.tsx +++ b/src/ui/Header.tsx @@ -6,10 +6,12 @@ import { Row } from "./Row.tsx"; import { PropsWithChildren } from "react"; import { useUser, useLogout } from "../hooks/useAuth.ts"; import packageInfo from "../../package.json"; +import { useHasPermission } from "../hooks/usePermissions.ts"; export function Header() { const { preferred_username } = useUser(); const logout = useLogout(); + const activeSettings = useHasPermission("ACCESS_SETTINGS"); return ( @@ -29,9 +31,11 @@ export function Header() { {preferred_username} - - - + {activeSettings && ( + + + + )} logout({ From 0ed55e73a0bba3df817fb4d79a2fd1cbfd6452ca Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 08:30:30 +0200 Subject: [PATCH 05/14] fix - finalize issue --- src/pages/UnauthorizedPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/UnauthorizedPage.tsx b/src/pages/UnauthorizedPage.tsx index fdce885..1968ceb 100644 --- a/src/pages/UnauthorizedPage.tsx +++ b/src/pages/UnauthorizedPage.tsx @@ -16,7 +16,7 @@ export function UnauthorizedPage() { > - {"Vous n'avez pas les droits nécessaires pour accéder à "} + {"Vous n'êtes pas autoisé à accéder à "} From 1f8f2a24f9448b8a4953f4c6e1f50d0a548d34c4 Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 09:03:28 +0200 Subject: [PATCH 06/14] fix - give admin role for guest in noauth mode --- src/functions/oidc.ts | 2 +- src/pages/Logout.tsx | 38 ++++++++++++++++++++++++++++++++++ src/pages/UnauthorizedPage.tsx | 2 +- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/pages/Logout.tsx diff --git a/src/functions/oidc.ts b/src/functions/oidc.ts index 0ff8112..8e70525 100644 --- a/src/functions/oidc.ts +++ b/src/functions/oidc.ts @@ -7,7 +7,7 @@ type TokenInfo = { }; const guestUser: TokenInfo = { - inseegroupedefaut: [], + inseegroupedefaut: [import.meta.env.VITE_ADMIN_LDAP_ROLE], preferred_username: "Guest", }; diff --git a/src/pages/Logout.tsx b/src/pages/Logout.tsx new file mode 100644 index 0000000..ab1e66b --- /dev/null +++ b/src/pages/Logout.tsx @@ -0,0 +1,38 @@ +import { Stack, Typography, Box } from "@mui/material"; +import { Row } from "../ui/Row"; + +export function LogoutPage() { + return ( + <> + + + {"Vous avez été deconnecté,"} + + + + {"pour revenir sur "} + + + + Platine + + Gestion + + , + + + {"cliquez ici"} + + + + ); +} diff --git a/src/pages/UnauthorizedPage.tsx b/src/pages/UnauthorizedPage.tsx index 1968ceb..c3a98b8 100644 --- a/src/pages/UnauthorizedPage.tsx +++ b/src/pages/UnauthorizedPage.tsx @@ -16,7 +16,7 @@ export function UnauthorizedPage() { > - {"Vous n'êtes pas autoisé à accéder à "} + {"Vous n'êtes pas autorisé à accéder à "} From ec67d9c553a506721dd7dac251d5d0441034d178 Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 10:00:53 +0200 Subject: [PATCH 07/14] fix - handle isloading on searchsurveys --- .env | 10 +++++----- src/pages/Search/SearchSurveys.tsx | 14 ++++++++++++-- src/routes.tsx | 2 ++ src/ui/Header.tsx | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/.env b/.env index 6789606..158615a 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ VITE_API_ENDPOINT=http://localhost:8000 -VITE_AUTH_TYPE=anonymous -VITE_OIDC_CLIENT_ID= -VITE_OIDC_ISSUER=https://localhost:8000 -VITE_IDENTITY_PROVIDER= -VITE_ADMIN_LDAP_ROLE=admin +VITE_AUTH_TYPE=oidc +VITE_OIDC_CLIENT_ID=coleman-pilotage +VITE_OIDC_ISSUER=https://auth.insee.test/auth/realms/questionnaire-particuliers +VITE_IDENTITY_PROVIDER=insee-ssp +VITE_ADMIN_LDAP_ROLE=administrateur_Platine VITE_USER_LDAP_ROLE=user diff --git a/src/pages/Search/SearchSurveys.tsx b/src/pages/Search/SearchSurveys.tsx index 7f51f20..e35678a 100644 --- a/src/pages/Search/SearchSurveys.tsx +++ b/src/pages/Search/SearchSurveys.tsx @@ -1,4 +1,4 @@ -import { Box, CardActionArea, Stack } from "@mui/material"; +import { Box, CardActionArea, CircularProgress, Stack } from "@mui/material"; import { FilterListBySelector } from "../../ui/Search/FilterListBySelector.tsx"; import { Row } from "../../ui/Row.tsx"; import { useInfiniteFetchQuery } from "../../hooks/useFetchQuery.ts"; @@ -23,6 +23,7 @@ export const SearchSurveys = () => { results: surveys, hasNextPage, fetchNextPage, + isLoading, } = useInfiniteFetchQuery(endpoint, { query: useSearchFilterParams("surveys"), }); @@ -40,7 +41,16 @@ export const SearchSurveys = () => { - + {isLoading && ( + + + + )} + {!isLoading && surveys.length === 0 && ( + + Aucun résultat + + )} {surveys.map(s => (
diff --git a/src/routes.tsx b/src/routes.tsx index 8f40372..16083d8 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -12,6 +12,7 @@ import { SearchSurveyUnits } from "./pages/Search/SearchSurveyUnits.tsx"; import { SurveyUnitPage } from "./pages/SurveyUnitPage.tsx"; import { CreateContactPage } from "./pages/CreateContactPage.tsx"; import { UnauthorizedPage } from "./pages/UnauthorizedPage.tsx"; +import { LogoutPage } from "./pages/Logout.tsx"; export const routes: RouteObject[] = [ { @@ -39,6 +40,7 @@ export const routes: RouteObject[] = [ { path: "reglages", element: }, { path: "contacts/createContact", element: }, { path: "", element: }, + { path: "logout", element: }, ], }, ]; diff --git a/src/ui/Header.tsx b/src/ui/Header.tsx index 08677f6..2a89f5f 100644 --- a/src/ui/Header.tsx +++ b/src/ui/Header.tsx @@ -40,7 +40,7 @@ export function Header() { onClick={() => logout({ redirectTo: "specific url", - url: "", + url: "http://localhost:5173/logout", }) } > From 91e49b0c145a6cb7ba30b32202d7cd00287d2e35 Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 10:46:10 +0200 Subject: [PATCH 08/14] fix - add logout based on user activity --- .env | 10 +++++----- src/functions/listenActivity.ts | 7 +++++++ src/functions/oidc.ts | 33 ++++++++++++++++++++++++--------- src/hooks/useAuth.ts | 32 +++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 src/functions/listenActivity.ts diff --git a/.env b/.env index 158615a..6789606 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ VITE_API_ENDPOINT=http://localhost:8000 -VITE_AUTH_TYPE=oidc -VITE_OIDC_CLIENT_ID=coleman-pilotage -VITE_OIDC_ISSUER=https://auth.insee.test/auth/realms/questionnaire-particuliers -VITE_IDENTITY_PROVIDER=insee-ssp -VITE_ADMIN_LDAP_ROLE=administrateur_Platine +VITE_AUTH_TYPE=anonymous +VITE_OIDC_CLIENT_ID= +VITE_OIDC_ISSUER=https://localhost:8000 +VITE_IDENTITY_PROVIDER= +VITE_ADMIN_LDAP_ROLE=admin VITE_USER_LDAP_ROLE=user diff --git a/src/functions/listenActivity.ts b/src/functions/listenActivity.ts new file mode 100644 index 0000000..826b694 --- /dev/null +++ b/src/functions/listenActivity.ts @@ -0,0 +1,7 @@ +const defaultListener = () => console.log("User is active !"); +export const listenActivity = (listener = defaultListener) => { + const activityEvents = ["mousedown", "mousemove", "keydown", "scroll", "touchstart"]; + activityEvents.forEach(function (eventName) { + window.addEventListener(eventName, listener, false); + }); +}; diff --git a/src/functions/oidc.ts b/src/functions/oidc.ts index 8e70525..890aed4 100644 --- a/src/functions/oidc.ts +++ b/src/functions/oidc.ts @@ -11,6 +11,28 @@ const guestUser: TokenInfo = { preferred_username: "Guest", }; +const dummyOidc = { + isUserLoggedIn: true, + logout: () => (window.location.href = "/"), + oidcTokens: { + decodedIdToken: guestUser, + accessToken: "accessToken", + idToken: null, + refreshToken: null, + refreshTokenExpirationTime: null, + // accessTokenExpirationTime: Date.now() + 60 * 60 * 1000, + accessTokenExpirationTime: 60 * 1000, + }, + login: () => window.location.reload(), + getTokens: () => ({ + accessToken: "accessToken", + idToken: null, + refreshToken: null, + refreshTokenExpirationTime: null, + accessTokenExpirationTime: Date.now() + 60 * 60 * 1000, + }), +}; + const isOidc = import.meta.env.VITE_AUTH_TYPE === "oidc"; export const createAppOidc = () => { @@ -25,14 +47,7 @@ export const createAppOidc = () => { return { OidcProvider: Fragment, - useOidc: () => ({ - login: () => null, - isUserLoggedIn: true, - oidcTokens: { - decodedIdToken: guestUser, - accessToken: "accessToken", - }, - logout: () => (window.location.href = "/"), - }), + useOidc: () => dummyOidc, + prOidc: Promise.resolve(dummyOidc), }; }; diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index 6998d71..e88dbe9 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -1,7 +1,8 @@ import { useEffect } from "react"; import { createAppOidc } from "../functions/oidc.ts"; +import { listenActivity } from "../functions/listenActivity.ts"; -const { OidcProvider, useOidc } = createAppOidc(); +const { OidcProvider, prOidc, useOidc } = createAppOidc(); export const useHasRole = (role: string): boolean => { const { oidcTokens } = useOidc({ assertUserLoggedIn: true }); @@ -35,4 +36,33 @@ export function useIsAuthenticated() { return { isAuthenticated: isUserLoggedIn, tokens: oidcTokens }; } +prOidc.then(oidc => { + if (!oidc.isUserLoggedIn) { + return; + } + let timer: number | undefined; + + console.log(oidc.getTokens().accessTokenExpirationTime); + + const getDelayExpriationinMs = () => { + const expirationTime = oidc.getTokens().accessTokenExpirationTime; + console.log(expirationTime); + return expirationTime - Date.now(); + }; + + const logoutIfIdle = async () => { + clearTimeout(timer); + + timer = setTimeout(async () => { + await oidc.logout({ redirectTo: "specific url", url: "http://localhost:5173/logout" }); + }, getDelayExpriationinMs()); + }; + + // Initial call to set the logout timer + logoutIfIdle(); + + // Event listeners to reset timer on user activity + listenActivity(logoutIfIdle); +}); + export const AuthProvider = OidcProvider; From 9be0d535fcad608d8bc05f6e3a820f9b7946d33c Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 11:55:41 +0200 Subject: [PATCH 09/14] fix - add logout based on user activity --- .env | 10 +++++----- src/App.tsx | 1 - src/pages/Logout.tsx | 10 ++++++++-- src/routes.tsx | 16 ++++++++++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/.env b/.env index 6789606..158615a 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ VITE_API_ENDPOINT=http://localhost:8000 -VITE_AUTH_TYPE=anonymous -VITE_OIDC_CLIENT_ID= -VITE_OIDC_ISSUER=https://localhost:8000 -VITE_IDENTITY_PROVIDER= -VITE_ADMIN_LDAP_ROLE=admin +VITE_AUTH_TYPE=oidc +VITE_OIDC_CLIENT_ID=coleman-pilotage +VITE_OIDC_ISSUER=https://auth.insee.test/auth/realms/questionnaire-particuliers +VITE_IDENTITY_PROVIDER=insee-ssp +VITE_ADMIN_LDAP_ROLE=administrateur_Platine VITE_USER_LDAP_ROLE=user diff --git a/src/App.tsx b/src/App.tsx index a24c616..2b117cc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,7 +27,6 @@ function AuthenticatedApp() { const canAccessSite = useHasPermission("ACCESS_APP"); if (!canAccessSite) { - // TODO : Mettre un composant Unauthorized return ; } diff --git a/src/pages/Logout.tsx b/src/pages/Logout.tsx index ab1e66b..ded8915 100644 --- a/src/pages/Logout.tsx +++ b/src/pages/Logout.tsx @@ -1,5 +1,7 @@ -import { Stack, Typography, Box } from "@mui/material"; +import { Stack, Typography, Box, Link } from "@mui/material"; import { Row } from "../ui/Row"; +import { PropsWithChildren } from "react"; +import { Link as RouterLink } from "react-router-dom"; export function LogoutPage() { return ( @@ -29,10 +31,14 @@ export function LogoutPage() { , - + {"cliquez ici"} ); } + +const HomeLink = (props: PropsWithChildren) => { + return ; +}; diff --git a/src/routes.tsx b/src/routes.tsx index 16083d8..f0fb60b 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -56,3 +56,19 @@ export const unauthorizedRoutes: RouteObject[] = [ errorElement: , }, ]; + +/* export const unauthenticatedRoutes: RouteObject[] = [ + { + path: "/", + element: ( + + + + ), + errorElement: , + children: [ + { path: "logout", element: }, + { path: "", element: }, + ], + }, +]; */ From f2443bab59391718b5a8d79e9fa90cec988e73cd Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Fri, 12 Apr 2024 11:56:13 +0200 Subject: [PATCH 10/14] fix - add logout based on user activity --- .env | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 158615a..6789606 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ VITE_API_ENDPOINT=http://localhost:8000 -VITE_AUTH_TYPE=oidc -VITE_OIDC_CLIENT_ID=coleman-pilotage -VITE_OIDC_ISSUER=https://auth.insee.test/auth/realms/questionnaire-particuliers -VITE_IDENTITY_PROVIDER=insee-ssp -VITE_ADMIN_LDAP_ROLE=administrateur_Platine +VITE_AUTH_TYPE=anonymous +VITE_OIDC_CLIENT_ID= +VITE_OIDC_ISSUER=https://localhost:8000 +VITE_IDENTITY_PROVIDER= +VITE_ADMIN_LDAP_ROLE=admin VITE_USER_LDAP_ROLE=user From b25db0c81fefac499c0905a032146356cfc1666f Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Tue, 16 Apr 2024 12:53:17 +0200 Subject: [PATCH 11/14] fix - update oidc spa and clean --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebf507b..0512633 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@mui/material": "^5.14.10", "@tanstack/react-query": "^5.17.15", "date-fns": "^3.3.1", - "oidc-spa": "^4.0.0", + "oidc-spa": "^4.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.50.0", From 96f5a663b39451a967d5f05c0f3cd8c455de2ad5 Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Tue, 16 Apr 2024 15:21:50 +0200 Subject: [PATCH 12/14] fix - rework logout flow --- .env | 1 + src/App.tsx | 17 ---------- src/functions/oidc.ts | 3 +- src/hooks/useAuth.ts | 64 ++++++++++++++++++++----------------- src/hooks/usePermissions.ts | 6 ++-- src/routes.tsx | 27 ++++++++++++---- src/ui/Header.tsx | 28 ++++++++-------- src/ui/Layout.tsx | 22 +++++++++++++ src/vite-env.d.ts | 1 + 9 files changed, 99 insertions(+), 70 deletions(-) diff --git a/.env b/.env index 6789606..31a4f9b 100644 --- a/.env +++ b/.env @@ -5,3 +5,4 @@ VITE_OIDC_ISSUER=https://localhost:8000 VITE_IDENTITY_PROVIDER= VITE_ADMIN_LDAP_ROLE=admin VITE_USER_LDAP_ROLE=user +VITE_APP_URL=http://localhost:5173 diff --git a/src/App.tsx b/src/App.tsx index 2b117cc..6e29e97 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,29 +1,12 @@ -import { CircularProgress } from "@mui/material"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { routes, unauthorizedRoutes } from "./routes"; -import { useIsAuthenticated } from "./hooks/useAuth"; import { useHasPermission } from "./hooks/usePermissions"; import "./App.css"; -import { Row } from "./ui/Row"; const router = createBrowserRouter(routes); const unauthorizedRouter = createBrowserRouter(unauthorizedRoutes); export function App() { - const { isAuthenticated } = useIsAuthenticated(); - - if (!isAuthenticated) { - return ( - - - - ); - } - - return ; -} - -function AuthenticatedApp() { const canAccessSite = useHasPermission("ACCESS_APP"); if (!canAccessSite) { diff --git a/src/functions/oidc.ts b/src/functions/oidc.ts index 890aed4..66e39da 100644 --- a/src/functions/oidc.ts +++ b/src/functions/oidc.ts @@ -29,7 +29,8 @@ const dummyOidc = { idToken: null, refreshToken: null, refreshTokenExpirationTime: null, - accessTokenExpirationTime: Date.now() + 60 * 60 * 1000, + //accessTokenExpirationTime: Date.now() + 60 * 60 * 1000, + accessTokenExpirationTime: 60 * 1000, }), }; diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index e88dbe9..ee3fbff 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -4,6 +4,35 @@ import { listenActivity } from "../functions/listenActivity.ts"; const { OidcProvider, prOidc, useOidc } = createAppOidc(); +prOidc.then(oidc => { + if (!oidc.isUserLoggedIn) { + return; + } + let timer: ReturnType | undefined; + + console.log(oidc.getTokens().accessTokenExpirationTime); + + const getDelayExpriationinMs = () => { + const expirationTime = oidc.getTokens().accessTokenExpirationTime; + console.log(expirationTime); + return expirationTime - Date.now(); + }; + + const logoutIfIdle = async () => { + clearTimeout(timer); + + timer = setTimeout(async () => { + await oidc.logout({ redirectTo: "specific url", url: `${import.meta.env.VITE_APP_URL}/logout` }); + }, getDelayExpriationinMs()); + }; + + // Initial call to set the logout timer + logoutIfIdle(); + + // Event listeners to reset timer on user activity + listenActivity(logoutIfIdle); +}); + export const useHasRole = (role: string): boolean => { const { oidcTokens } = useOidc({ assertUserLoggedIn: true }); return oidcTokens.decodedIdToken.inseegroupedefaut.includes(role); @@ -17,8 +46,12 @@ export const useUser = () => { return useOidc({ assertUserLoggedIn: true }).oidcTokens.decodedIdToken; }; +export const useMaybeUser = () => { + return useOidc({ assertUserLoggedIn: false })?.oidcTokens?.decodedIdToken; +}; + export const useLogout = () => { - return useOidc({ assertUserLoggedIn: true }).logout; + return useOidc({ assertUserLoggedIn: false }).logout; }; export function useIsAuthenticated() { @@ -36,33 +69,4 @@ export function useIsAuthenticated() { return { isAuthenticated: isUserLoggedIn, tokens: oidcTokens }; } -prOidc.then(oidc => { - if (!oidc.isUserLoggedIn) { - return; - } - let timer: number | undefined; - - console.log(oidc.getTokens().accessTokenExpirationTime); - - const getDelayExpriationinMs = () => { - const expirationTime = oidc.getTokens().accessTokenExpirationTime; - console.log(expirationTime); - return expirationTime - Date.now(); - }; - - const logoutIfIdle = async () => { - clearTimeout(timer); - - timer = setTimeout(async () => { - await oidc.logout({ redirectTo: "specific url", url: "http://localhost:5173/logout" }); - }, getDelayExpriationinMs()); - }; - - // Initial call to set the logout timer - logoutIfIdle(); - - // Event listeners to reset timer on user activity - listenActivity(logoutIfIdle); -}); - export const AuthProvider = OidcProvider; diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts index e556f5a..9d06f82 100644 --- a/src/hooks/usePermissions.ts +++ b/src/hooks/usePermissions.ts @@ -1,4 +1,4 @@ -import { useUser } from "./useAuth"; +import { useMaybeUser, useUser } from "./useAuth"; type User = ReturnType; type PermissionRequirement = string[] | ((user: User) => boolean); @@ -12,11 +12,11 @@ const permissions = { } satisfies Record; export const useHasPermission = (permissionKey: keyof typeof permissions) => { - const user = useUser(); + const user = useMaybeUser(); const permission = permissions[permissionKey]; // For unknown permission, refuse access by default - if (!permission) { + if (!permission || !user) { return false; } diff --git a/src/routes.tsx b/src/routes.tsx index f0fb60b..fbe5ecc 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -1,7 +1,7 @@ import { SearchPage } from "./pages/SearchPage"; import { Home } from "./pages/Home.tsx"; import { Outlet, redirect, RouteObject } from "react-router-dom"; -import { Layout } from "./ui/Layout"; +import { Layout, LayoutWithAuth } from "./ui/Layout"; import { PageError } from "./ui/PageError"; import { SurveyPage } from "./pages/SurveyPage"; import { ContactPage } from "./pages/ContactPage"; @@ -16,12 +16,20 @@ import { LogoutPage } from "./pages/Logout.tsx"; export const routes: RouteObject[] = [ { - path: "/", + path: "logout", element: ( - + ), + }, + { + path: "/", + element: ( + + + + ), errorElement: , children: [ { @@ -40,19 +48,26 @@ export const routes: RouteObject[] = [ { path: "reglages", element: }, { path: "contacts/createContact", element: }, { path: "", element: }, - { path: "logout", element: }, ], }, ]; export const unauthorizedRoutes: RouteObject[] = [ { - path: "/*", + path: "/logout", element: ( - + ), + }, + { + path: "/*", + element: ( + + + + ), errorElement: , }, ]; diff --git a/src/ui/Header.tsx b/src/ui/Header.tsx index 2a89f5f..fed957b 100644 --- a/src/ui/Header.tsx +++ b/src/ui/Header.tsx @@ -4,12 +4,12 @@ import ExitToAppIcon from "@mui/icons-material/ExitToApp"; import { Link as RouterLink } from "react-router-dom"; import { Row } from "./Row.tsx"; import { PropsWithChildren } from "react"; -import { useUser, useLogout } from "../hooks/useAuth.ts"; +import { useMaybeUser, useLogout } from "../hooks/useAuth.ts"; import packageInfo from "../../package.json"; import { useHasPermission } from "../hooks/usePermissions.ts"; export function Header() { - const { preferred_username } = useUser(); + const user = useMaybeUser(); const logout = useLogout(); const activeSettings = useHasPermission("ACCESS_SETTINGS"); @@ -30,22 +30,24 @@ export function Header() { - {preferred_username} + {user?.preferred_username} {activeSettings && ( )} - - logout({ - redirectTo: "specific url", - url: "http://localhost:5173/logout", - }) - } - > - - + {logout && ( + + logout({ + redirectTo: "specific url", + url: `${import.meta.env.VITE_APP_URL}/logout`, + }) + } + > + + + )} ); diff --git a/src/ui/Layout.tsx b/src/ui/Layout.tsx index 99256bd..7ebe8b4 100644 --- a/src/ui/Layout.tsx +++ b/src/ui/Layout.tsx @@ -1,5 +1,8 @@ import { type PropsWithChildren } from "react"; import { Header } from "./Header"; +import { useIsAuthenticated } from "../hooks/useAuth"; +import { CircularProgress } from "@mui/material"; +import { Row } from "../ui/Row"; export function Layout({ children }: PropsWithChildren) { return ( @@ -9,3 +12,22 @@ export function Layout({ children }: PropsWithChildren) { ); } + +export function LayoutWithAuth({ children }: PropsWithChildren) { + const { isAuthenticated } = useIsAuthenticated(); + + if (!isAuthenticated) { + return ( + + + + ); + } + + return ( + <> +
+ {children} + + ); +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index f230803..6b481f7 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -7,6 +7,7 @@ interface ImportMetaEnv { readonly VITE_IDENTITY_PROVIDER: string; readonly VITE_ADMIN_LDAP_ROLE: string; readonly VITE_USER_LDAP_ROLE: string; + readonly VITE_APP_URL: string; } interface ImportMeta { From 05b1d7b17823b836411e48e887d46b2b5471e052 Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Thu, 18 Apr 2024 18:18:27 +0200 Subject: [PATCH 13/14] upgrade version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0512633..8a50584 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "platine-management", "private": true, - "version": "1.0.16", + "version": "1.0.18", "type": "module", "scripts": { "dev": "vite", From e5548ed3333f514583815396a2e9dcdde157e46b Mon Sep 17 00:00:00 2001 From: Eric Thuaud Date: Tue, 30 Apr 2024 16:05:12 +0200 Subject: [PATCH 14/14] feat - implem autologout and mockoidc with upgrade oidc-spa --- package.json | 2 +- src/functions/autoLogoutCountdown.tsx | 65 +++++++++++++++++++++++++++ src/functions/listenActivity.ts | 7 --- src/functions/oidc.ts | 40 +++++------------ src/hooks/useAuth.ts | 34 +------------- src/main.tsx | 2 + src/vite-env.d.ts | 45 ++++++++++++++----- yarn.lock | 58 +++++++++++++++++++++--- 8 files changed, 165 insertions(+), 88 deletions(-) create mode 100644 src/functions/autoLogoutCountdown.tsx delete mode 100644 src/functions/listenActivity.ts diff --git a/package.json b/package.json index 0e9a7ae..7cf5876 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@mui/material": "^5.14.10", "@tanstack/react-query": "^5.17.15", "date-fns": "^3.3.1", - "oidc-spa": "^4.2.1", + "oidc-spa": "^4.6.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.50.0", diff --git a/src/functions/autoLogoutCountdown.tsx b/src/functions/autoLogoutCountdown.tsx new file mode 100644 index 0000000..ffee7bb --- /dev/null +++ b/src/functions/autoLogoutCountdown.tsx @@ -0,0 +1,65 @@ +import { Typography } from "@mui/material"; +import { useState, useEffect } from "react"; +import { useOidc } from "../hooks/useAuth"; + +export function AutoLogoutCountdown() { + const { isUserLoggedIn, subscribeToAutoLogoutCountdown } = useOidc(); + const [secondsLeft, setSecondsLeft] = useState(undefined); + + useEffect( + () => { + if (!isUserLoggedIn) { + return; + } + + const { unsubscribeFromAutoLogoutCountdown } = subscribeToAutoLogoutCountdown( + ({ secondsLeft }) => { + setSecondsLeft(secondsLeft === undefined || secondsLeft > 60 ? undefined : secondsLeft), + console.log(`seconds Left: ${secondsLeft}`); + }, + ); + + return () => { + console.log("unsuscribing"); + unsubscribeFromAutoLogoutCountdown(); + }; + }, + // NOTE: These dependency array could very well be empty + // we're just making react-hooks/exhaustive-deps happy. + // Unless you're hot swapping the oidc context isUserLoggedIn + // and subscribeToAutoLogoutCountdown never change for the + // lifetime of the app. + [isUserLoggedIn, subscribeToAutoLogoutCountdown], + ); + + if (secondsLeft === undefined) { + return null; + } + + return ( +
+
+ {"Vous êtes toujours là?"} + {`Vous allez être déconnecté(e) dans ${secondsLeft} sec.`} +
+
+ ); +} diff --git a/src/functions/listenActivity.ts b/src/functions/listenActivity.ts deleted file mode 100644 index 826b694..0000000 --- a/src/functions/listenActivity.ts +++ /dev/null @@ -1,7 +0,0 @@ -const defaultListener = () => console.log("User is active !"); -export const listenActivity = (listener = defaultListener) => { - const activityEvents = ["mousedown", "mousemove", "keydown", "scroll", "touchstart"]; - activityEvents.forEach(function (eventName) { - window.addEventListener(eventName, listener, false); - }); -}; diff --git a/src/functions/oidc.ts b/src/functions/oidc.ts index 66e39da..ef143c2 100644 --- a/src/functions/oidc.ts +++ b/src/functions/oidc.ts @@ -1,5 +1,5 @@ +import { createMockReactOidc } from "oidc-spa/mock/react"; import { createReactOidc } from "oidc-spa/react"; -import { Fragment } from "react"; type TokenInfo = { inseegroupedefaut: string[]; @@ -7,33 +7,10 @@ type TokenInfo = { }; const guestUser: TokenInfo = { - inseegroupedefaut: [import.meta.env.VITE_ADMIN_LDAP_ROLE], + inseegroupedefaut: [import.meta.env.VITE_USER_LDAP_ROLE], preferred_username: "Guest", }; -const dummyOidc = { - isUserLoggedIn: true, - logout: () => (window.location.href = "/"), - oidcTokens: { - decodedIdToken: guestUser, - accessToken: "accessToken", - idToken: null, - refreshToken: null, - refreshTokenExpirationTime: null, - // accessTokenExpirationTime: Date.now() + 60 * 60 * 1000, - accessTokenExpirationTime: 60 * 1000, - }, - login: () => window.location.reload(), - getTokens: () => ({ - accessToken: "accessToken", - idToken: null, - refreshToken: null, - refreshTokenExpirationTime: null, - //accessTokenExpirationTime: Date.now() + 60 * 60 * 1000, - accessTokenExpirationTime: 60 * 1000, - }), -}; - const isOidc = import.meta.env.VITE_AUTH_TYPE === "oidc"; export const createAppOidc = () => { @@ -42,13 +19,16 @@ export const createAppOidc = () => { issuerUri: import.meta.env.VITE_OIDC_ISSUER, clientId: import.meta.env.VITE_OIDC_CLIENT_ID, publicUrl: "/", + autoLogoutParams: { redirectTo: "specific url", url: `${import.meta.env.VITE_APP_URL}/logout` }, extraQueryParams: { kc_idp_hint: import.meta.env.VITE_IDENTITY_PROVIDER }, }); } - return { - OidcProvider: Fragment, - useOidc: () => dummyOidc, - prOidc: Promise.resolve(dummyOidc), - }; + return createMockReactOidc({ + isUserInitiallyLoggedIn: true, + mockedTokens: { + decodedIdToken: guestUser, + accessToken: "accessToken", + }, + }); }; diff --git a/src/hooks/useAuth.ts b/src/hooks/useAuth.ts index ee3fbff..215c49b 100644 --- a/src/hooks/useAuth.ts +++ b/src/hooks/useAuth.ts @@ -1,37 +1,7 @@ import { useEffect } from "react"; import { createAppOidc } from "../functions/oidc.ts"; -import { listenActivity } from "../functions/listenActivity.ts"; -const { OidcProvider, prOidc, useOidc } = createAppOidc(); - -prOidc.then(oidc => { - if (!oidc.isUserLoggedIn) { - return; - } - let timer: ReturnType | undefined; - - console.log(oidc.getTokens().accessTokenExpirationTime); - - const getDelayExpriationinMs = () => { - const expirationTime = oidc.getTokens().accessTokenExpirationTime; - console.log(expirationTime); - return expirationTime - Date.now(); - }; - - const logoutIfIdle = async () => { - clearTimeout(timer); - - timer = setTimeout(async () => { - await oidc.logout({ redirectTo: "specific url", url: `${import.meta.env.VITE_APP_URL}/logout` }); - }, getDelayExpriationinMs()); - }; - - // Initial call to set the logout timer - logoutIfIdle(); - - // Event listeners to reset timer on user activity - listenActivity(logoutIfIdle); -}); +export const { OidcProvider, prOidc, useOidc } = createAppOidc(); export const useHasRole = (role: string): boolean => { const { oidcTokens } = useOidc({ assertUserLoggedIn: true }); @@ -47,7 +17,7 @@ export const useUser = () => { }; export const useMaybeUser = () => { - return useOidc({ assertUserLoggedIn: false })?.oidcTokens?.decodedIdToken; + return useOidc({ assertUserLoggedIn: false }).oidcTokens?.decodedIdToken; }; export const useLogout = () => { diff --git a/src/main.tsx b/src/main.tsx index df58f51..6ff0ae0 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,6 +4,7 @@ import { PlatineTheme } from "./theme.tsx"; import { StrictMode } from "react"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { AuthProvider } from "./hooks/useAuth.ts"; +import { AutoLogoutCountdown } from "./functions/autoLogoutCountdown.tsx"; const queryClient = new QueryClient({ defaultOptions: { @@ -18,6 +19,7 @@ const queryClient = new QueryClient({ ReactDOM.createRoot(document.getElementById("root")!).render( + diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 6b481f7..ee62647 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1,17 +1,40 @@ -/// -interface ImportMetaEnv { - readonly VITE_API_ENDPOINT: string; - readonly VITE_AUTH_TYPE: string; - readonly VITE_OIDC_CLIENT_ID: string; - readonly VITE_OIDC_ISSUER: string; - readonly VITE_IDENTITY_PROVIDER: string; - readonly VITE_ADMIN_LDAP_ROLE: string; - readonly VITE_USER_LDAP_ROLE: string; - readonly VITE_APP_URL: string; +/// +type ImportMetaEnv = { + // Auto-generated by `npx vite-envs update-types` and hot-reloaded by the `vite-env` plugin + VITE_API_ENDPOINT: string + VITE_AUTH_TYPE: string + VITE_OIDC_CLIENT_ID: string + VITE_OIDC_ISSUER: string + VITE_IDENTITY_PROVIDER: string + VITE_ADMIN_LDAP_ROLE: string + VITE_USER_LDAP_ROLE: string + VITE_APP_URL: string + BASE_URL: string + MODE: string + DEV: boolean + PROD: boolean + // @user-defined-start + /* + * Here you can define your own special variables + * that would be available on `import.meta.env` but + * that vite-envs does not know about. + * This section will be preserved thanks to the special comments. + * Example: + */ + SSR: boolean; + // @user-defined-end } interface ImportMeta { - readonly env: ImportMetaEnv; + // Auto-generated by `npx vite-envs update-types` + + url: string + + readonly hot?: import('vite-envs/types/hot').ViteHotContext + + readonly env: ImportMetaEnv + + glob: import('vite-envs/types/importGlob').ImportGlobFunction } type ObjectKeys = T extends object diff --git a/yarn.lock b/yarn.lock index de52dbd..1a2a210 100644 --- a/yarn.lock +++ b/yarn.lock @@ -227,6 +227,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.23.8", "@babel/runtime@^7.24.4": + version "7.24.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.4.tgz#de795accd698007a66ba44add6cc86542aff1edd" + integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" @@ -1626,6 +1633,14 @@ fast-shallow-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== +fast-unique-numbers@^8.0.13: + version "8.0.13" + resolved "https://registry.yarnpkg.com/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz#3c87232061ff5f408a216e1f0121232f76f695d7" + integrity sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g== + dependencies: + "@babel/runtime" "^7.23.8" + tslib "^2.6.2" + fastest-stable-stringify@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" @@ -2376,7 +2391,7 @@ object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -oidc-client-ts@^2.3.0: +oidc-client-ts@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/oidc-client-ts/-/oidc-client-ts-2.4.0.tgz#764c8a33de542026e2798de9849ce8049047d7e5" integrity sha512-WijhkTrlXK2VvgGoakWJiBdfIsVGz6CFzgjNNqZU1hPKV2kyeEaJgLs7RwuiSp2WhLfWBQuLvr2SxVlZnk3N1w== @@ -2384,14 +2399,15 @@ oidc-client-ts@^2.3.0: crypto-js "^4.2.0" jwt-decode "^3.1.2" -oidc-spa@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/oidc-spa/-/oidc-spa-4.0.0.tgz#7cec1683686cd6f2b9c85547107b19b6b54ffd39" - integrity sha512-Zy386BfS/LbkUopNTA1xFCWYIMc7fFrQ1Iyc58vt+2dAezTAt15F6YTrYGXGCa4P0q8SpO6Avu8/OmHyO67d9w== +oidc-spa@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/oidc-spa/-/oidc-spa-4.6.0.tgz#3482e14c405b0ef9c7673ae7be4c1928d0b06a65" + integrity sha512-a1y+PSBtlhzyKJ7ucGx9Rp+aJhV2cL36rmO/imIHkfb4ig/5xOQtzl9Ee9hRbAIrwVAu/lpR9PfUXTq2bLrG2Q== dependencies: jwt-decode "^3.1.2" - oidc-client-ts "^2.3.0" + oidc-client-ts "2.4.0" tsafe "^1.6.5" + worker-timers "^7.1.7" once@^1.3.0: version "1.4.0" @@ -2926,7 +2942,7 @@ tsafe@^1.6.5, tsafe@^1.6.6: resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.6.6.tgz#fd93e64d6eb13ef83ed1650669cc24bad4f5df9f" integrity sha512-gzkapsdbMNwBnTIjgO758GujLCj031IgHK/PKr2mrmkCSJMhSOR5FeOuSxKLMUoYc0vAA4RGEYYbjt/v6afD3g== -tslib@^2.1.0: +tslib@^2.1.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -3065,6 +3081,34 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +worker-timers-broker@^6.1.7: + version "6.1.7" + resolved "https://registry.yarnpkg.com/worker-timers-broker/-/worker-timers-broker-6.1.7.tgz#c570552f1576f81226dbeb0dc14bb64144c9597c" + integrity sha512-8hb4lSMAijDY/Dp/MOw9Hc2x6uU59XWFYjcWQgC4bai+sxcLXjeexd9aYKdYMFZPiPoieGzMYIs9WGpv2Co3eA== + dependencies: + "@babel/runtime" "^7.24.4" + fast-unique-numbers "^8.0.13" + tslib "^2.6.2" + worker-timers-worker "^7.0.70" + +worker-timers-worker@^7.0.70: + version "7.0.70" + resolved "https://registry.yarnpkg.com/worker-timers-worker/-/worker-timers-worker-7.0.70.tgz#064758e1ca3bed908950d152e3e3006595dd9600" + integrity sha512-lemWEME0RHB78hzGkkQcKfF6L82gqVhV3T9iY14jHBhbLxLq9t1RRCLmPDBZV7sdnUoW6Khkfn6coqPjgEK6cw== + dependencies: + "@babel/runtime" "^7.24.4" + tslib "^2.6.2" + +worker-timers@^7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/worker-timers/-/worker-timers-7.1.7.tgz#1119f6454cb7c8653097ffb66f592115fb6693ea" + integrity sha512-Dr4La61d94SjOA8P57h2LN8W3MXOVe/m1P7jER8cmuIy+JaDMqPttSwo6QRJFSK6YnG9cD6SU7J8m7CVlu8jlw== + dependencies: + "@babel/runtime" "^7.24.4" + tslib "^2.6.2" + worker-timers-broker "^6.1.7" + worker-timers-worker "^7.0.70" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"