absent-sapphire
absent-sapphire6mo ago

Authenticated now working properly

Hello, I have my app setup as follows:
<Routes>
<Route path="/register" element={<RegisterPage />} />
<Route path="/login" element={<LoginPage />} />
<Route
path="/forgot-password"
element={<ForgotPasswordPage />}
/>
<Route
path="/update-password"
element={<UpdatePasswordPage />}
/>
<Route
element={
<Authenticated
key="authenticated-layout"
fallback={<CatchAllNavigate to="/login" />}
>
<Layout>
<Outlet />
</Layout>
</Authenticated>
}
>
<Route index element={<Home />} />
<Route path="/customers">
<Route index element={<CustomerList />} />
<Route path="new" element={<CreateCustomer />} />
</Route>
<Route path="/events">
<Route index element={<EventList />} />
<Route path="new" element={<CreateEvent />} />
</Route>
</Route>
</Routes>
<Routes>
<Route path="/register" element={<RegisterPage />} />
<Route path="/login" element={<LoginPage />} />
<Route
path="/forgot-password"
element={<ForgotPasswordPage />}
/>
<Route
path="/update-password"
element={<UpdatePasswordPage />}
/>
<Route
element={
<Authenticated
key="authenticated-layout"
fallback={<CatchAllNavigate to="/login" />}
>
<Layout>
<Outlet />
</Layout>
</Authenticated>
}
>
<Route index element={<Home />} />
<Route path="/customers">
<Route index element={<CustomerList />} />
<Route path="new" element={<CreateCustomer />} />
</Route>
<Route path="/events">
<Route index element={<EventList />} />
<Route path="new" element={<CreateEvent />} />
</Route>
</Route>
</Routes>
However if I stay for example on /events/list page and wait for accessToken to expire and then navigate to /costumers page the data doesn't load because I'm no longer authenticated but <Authenticated /> component doesn't call check when I navigate from /events to /customers. How do I resolve this issue? Calling useIsAuthenticated hook goes into infinite render loop
7 Replies
kapa.ai
kapa.ai6mo ago
Hi @chachi. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Hmm, I don't know enough to give you a confident answer yet. However, for handling authentication and ensuring that your <Authenticated /> component reacts appropriately to changes in authentication status, you might want to review the documentation and examples provided by refine for best practices and troubleshooting tips. Specifically, looking into how the authProvider is implemented and ensuring it correctly handles session expiration and token renewal could be beneficial. Additionally, exploring the use of context or state management to trigger re-authentication checks across route changes might help resolve the issue you're facing. For more detailed guidance and examples on implementing authentication with refine, including the use of <Authenticated /> component and authProvider, you can refer to the official documentation here: Refine Docs on Authentication (https://refine.dev/docs/). Since the extracts provided do not contain a direct solution to the issue of the <Authenticated /> component not re-checking authentication status on route changes, I recommend exploring the documentation and community discussions for insights and potential workarounds that have worked for others in similar situations. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai6mo ago
<@95552725294518272> kapa.ai is still learning and improving, please let us know how it did by reacting below
genetic-orange
genetic-orange5mo ago
Hello @chachi, can you share your auth provider with us?
absent-sapphire
absent-sapphire5mo ago
Hey @Alican Erdurmaz, sure, here is my check function:
check: async () => {
try {
const accessToken = localStorage.getItem('accessToken');
if (!accessToken) {
return {
authenticated: false,
redirectTo: '/login',
};
}

const checkResponse = await fetch(AUTH_API_BASE_URL + '/check', {
method: 'GET',
cache: 'no-cache',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
});

if (checkResponse.status === 200) {
const resJson = await checkResponse.json();
sessionStorage.setItem('id', resJson.id);

return {
authenticated: true,
redirectTo: '/',
};
}

if (checkResponse.status === 401) {
const refreshResponse = await fetch(AUTH_API_BASE_URL + '/refresh', {
method: 'GET',
cache: 'no-cache',
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
});

if (refreshResponse.status === 200) {
const resJson = await refreshResponse.json();
localStorage.setItem('accessToken', resJson.accessToken);

return {
authenticated: true,
redirectTo: '/',
};
}
}
return {
authenticated: false,
redirectTo: '/login',
};
} catch (e) {
const error = e as Error;

return {
authenticated: false,
redirectTo: '/login',
error: error,
};
}
},
check: async () => {
try {
const accessToken = localStorage.getItem('accessToken');
if (!accessToken) {
return {
authenticated: false,
redirectTo: '/login',
};
}

const checkResponse = await fetch(AUTH_API_BASE_URL + '/check', {
method: 'GET',
cache: 'no-cache',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
});

if (checkResponse.status === 200) {
const resJson = await checkResponse.json();
sessionStorage.setItem('id', resJson.id);

return {
authenticated: true,
redirectTo: '/',
};
}

if (checkResponse.status === 401) {
const refreshResponse = await fetch(AUTH_API_BASE_URL + '/refresh', {
method: 'GET',
cache: 'no-cache',
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
});

if (refreshResponse.status === 200) {
const resJson = await refreshResponse.json();
localStorage.setItem('accessToken', resJson.accessToken);

return {
authenticated: true,
redirectTo: '/',
};
}
}
return {
authenticated: false,
redirectTo: '/login',
};
} catch (e) {
const error = e as Error;

return {
authenticated: false,
redirectTo: '/login',
error: error,
};
}
},
And here the whole authProvider:
genetic-orange
genetic-orange5mo ago
Code seems okay, I need time to debug. thanks for sharing issue with us Hello again @chachi, Sorry for late response. <Authenticted /> component not sent request on every route change (not calling authProvider.check), you can use authProvider.onError component and after API returns 403 you can logout your user and redirect to login page
absent-sapphire
absent-sapphire5mo ago
@Alican Erdurmaz Even when the user is just navigating between resources the Authenticated component doesn't call the check method but that doesn't mean the user is inactive. I don't want to logout the user every 30 minutes (expiration of my accessToken) because of this. So I'm guessing the only solution is to use useIsAuthenticated on every page that requires being authenticated?
genetic-orange
genetic-orange5mo ago
Yes you can use useIsAuthenticated but, I believe using authProvider.onError is the best practice to handle this kind of use cases. When the API returns 401 or 403, you can logout the user in the onError method, so you don't need to request the API on every page transition