AuthProvider context is undefined - Cannot read properties of undefined (reading 'activeNavigator')
Hi all! I'm on version 3.3.0 and for some reason I'm getting the warning message below, which is being thrown from inside my Layout component.
[!WARNING] AuthProvider context is undefined, please verify you are calling useAuth() as child of a <AuthProvider> component.
Then later on I'm getting this error
[!CAUTION] TypeError: Cannot read properties of undefined (reading 'activeNavigator')
We do have other applications using this same setup that seem to work fine so I've been really scratching my head about what could be wrong. Would appreciate if anyone could give this setup a look-over and let me know if I'm missing something obvious. Here's the basic code setup.
// main.tsx
import { onSigninCallback } from '@my-company/auth';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { AuthProvider } from 'react-oidc-context';
import { Provider as StoreProvider } from 'react-redux';
import { BrowserRouter, Route } from 'react-router';
import { Layout } from '~/components/Layout';
import { userManager } from '~/oidc';
import { NotFound } from '~/pages/NotFound';
import { Root } from '~/pages/Root';
import { store } from '~/store';
const root = document.getElementById('root')!;
async function enableMocking() {
if (import.meta.env.VITE_ENABLE_MOCKS === 'true') {
const { worker } = await import('./mocks/browser');
return worker.start({
serviceWorker: {
url: '/mockServiceWorker.js',
},
});
}
}
enableMocking().then(() => {
return createRoot(root).render(
<StrictMode>
<BrowserRouter>
<AuthProvider userManager={userManager} onSigninCallback={() => onSigninCallback()}>
<StoreProvider store={store}>
<Route element={<Layout />}>
<Route index element={<div>hi</div>} />
</Route>
<Route path="*" element={<div>Not found</div>} />
</StoreProvider>
</AuthProvider>
</BrowserRouter>
</StrictMode>
);
});
// Layout.tsx
import { AuthenticationWrapper, AuthorizationWrapper, Roles } from '@my-company/auth';
import { Outlet } from 'react-router';
export const Layout = () => {
return (
<AuthenticationWrapper loadingComponent={<div>Loading...</div>} errorComponent={<div>You got problems...</div>}>
<AuthorizationWrapper requiredRole={Roles.SOME_ROLE}>
<Outlet />
</AuthorizationWrapper>
</AuthenticationWrapper>
);
};
// AuthenticationWrapper.tsx
import { PropsWithChildren } from 'react';
import { useAutoSignin } from 'react-oidc-context';
type Props = {
loadingComponent?: React.ReactNode;
errorComponent?: React.ReactNode;
};
export function AuthenticationWrapper({ children, loadingComponent, errorComponent }: PropsWithChildren<Props>) {
const { isAuthenticated, isLoading, error } = useAutoSignin();
if (isLoading) {
const LoadingComponent = () => loadingComponent ?? null;
return <LoadingComponent />;
}
if (error) {
const ErrorComponent = () => errorComponent ?? null;
return <ErrorComponent />;
}
if (isAuthenticated) {
return children;
}
return null;
}
// AuthorizationWrapper.tsx
import { getUser, type Role } from '@my-company/auth';
import { PropsWithChildren, useEffect, useState } from 'react';
type AuthorizationWrapperProps = PropsWithChildren<{
requiredRole?: Role;
unauthorizedComponent?: React.ReactNode;
}>;
export function AuthorizationWrapper({ requiredRole, unauthorizedComponent, children }: AuthorizationWrapperProps) {
const user = getUser(); // returning {id: "[email protected]", email: "[email protected]", reference: string, roles: ["SOME_ROLE"] }
const [isAuthorized, setIsAuthorized] = useState<boolean | undefined>(undefined);
useEffect(() => {
if (!requiredRole) {
setIsAuthorized(true);
return;
}
if (!user) {
setIsAuthorized(false);
return;
}
if (!user.roles.length) {
setIsAuthorized(false);
return;
}
if (user.roles.includes(requiredRole)) {
setIsAuthorized(true);
return;
}
setIsAuthorized(false);
}, [user, requiredRole]);
if (typeof isAuthorized === 'undefined') {
return null;
}
if (isAuthorized) {
return children;
}
return unauthorizedComponent ?? <div>Unauthorized</div>;
}
// oidc.ts
import { UserManager } from 'oidc-client-ts';
const CLIENT_ID = 'my-client';
const IDP_ID = 'google-saml';
export const userManager = new UserManager({
authority: "https://test.my-company.com/auth/realms/my-realm",
client_id: CLIENT_ID,
redirect_uri: `${window.location.origin}${window.location.pathname}`,
extraQueryParams: { kc_idp_hint: IDP_ID },
});
Hi @jgf5013 - are you able to reproduce this issue in the sample repo? (after making the minimal React code changes to mirror your setup)
Hi @jgf5013 - are you able to reproduce this issue in the sample repo? (after making the minimal React code changes to mirror your setup)
Unfortunately, I'm not, no - the issue is only present when I deploy to our test/PR environment. Locally, it's completely fine. This makes me think it's probably related to a configuration or some sort of relative vs absolute path configuration etc. I can completely understand if there's no chance of helping without a minimally reproducible version but am also curious if anyone else has seen the same thing with another project or if anyone can spot a misconfiguration somewhere.
All using code must be called within a child of the AuthContext, that is standard React behavior. First double check that this is the case. If it is: double check you have only one version of this library and you are consequently using this only one library...
All using code must be called within a child of the
AuthContext, that is standard React behavior. First double check that this is the case. If it is: double check you have only one version of this library and you are consequently using this only one library...
@pamapa yup - confirmed both are the case.
@jgf5013 since you can't reproduce it locally, and it only happens in your "test" env, would focus on narrowing down the configuration differences between those envs.