1
0
forked from baron/baron-sso
Files
baron-sso/devfront/src/features/auth/AuthGuard.tsx

89 lines
2.1 KiB
TypeScript

import { useEffect, useState } from "react";
import { useAuth } from "react-oidc-context";
import { Navigate, Outlet } from "react-router-dom";
import { userManager } from "../../lib/auth";
import {
findPersistedOidcUser,
isValidOidcSessionUser,
} from "../../lib/oidcStorage";
export default function AuthGuard() {
const auth = useAuth();
const hasActiveAuthUser =
auth.isAuthenticated && isValidOidcSessionUser(auth.user);
const [hasStoredUser, setHasStoredUser] = useState<boolean | null>(() =>
findPersistedOidcUser() ? true : null,
);
const isTestMode =
(window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean })
._IS_TEST_MODE === true;
useEffect(() => {
let cancelled = false;
if (isTestMode) {
setHasStoredUser(true);
return () => {
cancelled = true;
};
}
const persistedUser = findPersistedOidcUser();
if (persistedUser) {
setHasStoredUser(true);
return () => {
cancelled = true;
};
}
void userManager
.getUser()
.then((user) => {
if (!cancelled) {
setHasStoredUser(isValidOidcSessionUser(user));
}
})
.catch(() => {
if (!cancelled) {
setHasStoredUser(false);
}
});
return () => {
cancelled = true;
};
}, [isTestMode]);
if (isTestMode) {
return <Outlet />;
}
if (auth.isLoading || auth.activeNavigator || hasStoredUser === null) {
return <div>Loading...</div>;
}
if (auth.error) {
return (
<div className="flex min-h-screen flex-col items-center justify-center p-4 text-center">
<div className="mb-4 text-red-500">
<h2 className="text-xl font-bold">Authentication Error</h2>
<p>{auth.error.message}</p>
</div>
<button
type="button"
onClick={() => void auth.signinRedirect()}
className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
>
Start Login Again
</button>
</div>
);
}
if (!hasActiveAuthUser && !hasStoredUser) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
}