Authenticated loaders #9327
Replies: 6 comments 28 replies
-
would really like to kknow the answer to this as well., Looked over the documents and see no mention of this. Basically need to make sure config and auth is ran BEFORE any sub routes. right now they are run in parallel and its making fetch calls with-out having the bearer tokens |
Beta Was this translation helpful? Give feedback.
-
Adding this here for those stumbling onto this conversation Might be worth nothing how other frameworks do it: |
Beta Was this translation helpful? Give feedback.
-
Hey folks! At the moment, just like Remix, all loaders are called in parallel and you should be checking stuff like auth state in all of your loaders. This is also important because with nested routing, re-used routes will not have their loaders re-executed. So if you only check in the We have some ideas floating around internally on ways to solve this, so we'll update this discussion as soon as we start to solidify our ideas there. |
Beta Was this translation helpful? Give feedback.
-
We're designing the middleware API right now that will meet this use case and will be publishing an RFC soon. You can see its progress on the roadmap here: https://github.com/orgs/remix-run/projects/5/views/1 |
Beta Was this translation helpful? Give feedback.
-
Something like this can work: let resolveAuthenticatedPromise: (result: unknown) => void;
let authenticatedPromise = new Promise((resolve) => {
resolveAuthenticatedPromise = resolve;
});
/** Call this function when the user is authenticated */
export function authenticateUser() {
resolveAuthenticatedPromise(undefined);
}
/**
* Makes sure the user is authenticated, useful to avoid 401 calls to the api
*
* @example
* const loader = async () => {
* return defer({ data: ensureAuthenticated().then(() => fetchData()) });
* };
*/
export async function ensureAuthenticated() {
return authenticatedPromise;
} |
Beta Was this translation helpful? Give feedback.
-
How does everyone do the permissions module? export const routers= [
{ path: '/', element: <Navigate to="/realtime" replace /> },
{ path: '/login', element: <Login /> },
{
element: <BasicLayout />,
children:[]
},
{ path: '*', element: <NotFound /> },
]
const BasicLayout =()=> {
const {userInfo, isLoading,fetchUserInfo} = useStore() // zustand
let location = useLocation();
useEffect(() => {
if (!localStorage.getItem('token')) {
navigate('/login')
}
if(!userInfo){
fetchUserInfo()
}
//... also fetch other global data
}, [location.key])
if (isLoading || otherGlobalDataLoading) {
return <LoadingOverlay />
}
return <MyErrorBoundary>
<Suspense fallback={<Loader />}>
<Outlet />
</Suspense>
</MyErrorBoundary>
}
const App = ()=> {
return <Suspense>
<RouterProvider router={_router} />
</Suspense>
}
// axios.ts
import { router } from './App'
router.navigate('/login') // token 401
localstorage.delete('token') // option
// Login.tsx
// Refresh the page directly, this is the easiest way, otherwise you have to reset all the state, e.g. userInfo globalData
const doLogin => window.location.replace('/') |
Beta Was this translation helpful? Give feedback.
-
It's my understanding that all matched loaders are fetched in parallel. Is there a best practice for solving the problem that we only want to execute certain loaders if a user is authenticated?
Beta Was this translation helpful? Give feedback.
All reactions