Eyal Alfasi
Eyal Alfasi3mo ago

Authentication in Remix Loader with Convex Auth

I'm using Convex and Convex Auth in a Remix app, and I want to check if a user is authenticated in a Remix loader to redirect unauthenticated users to the login page. I'm trying this:
export const loader: LoaderFunction = () => {
const convex = new ConvexClient(CONVEX_URL);
const currentUser = convex.query(api.users.me, {});

if (currentUser === null) {
return redirect("/login");
}

return null;
};
export const loader: LoaderFunction = () => {
const convex = new ConvexClient(CONVEX_URL);
const currentUser = convex.query(api.users.me, {});

if (currentUser === null) {
return redirect("/login");
}

return null;
};
But currentUser always returns null. Using the useConvexAuth hook in a component does eventually return isAuthenticated as true so I know the login worked. Here’s my users.me query:
export const me = query({
handler: async (ctx) => {
const userId = await getAuthUserId(ctx);
if (userId === null) {
return null;
}
return await ctx.db.get(userId);
},
});
export const me = query({
handler: async (ctx) => {
const userId = await getAuthUserId(ctx);
if (userId === null) {
return null;
}
return await ctx.db.get(userId);
},
});
How can I correctly check user authentication in the loader? Or should I handle this redirect logic in remix + convex auth differently? Thanks in advance 🙂
15 Replies
Convex Bot
Convex Bot3mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
sonandmjy
sonandmjy4w ago
I'm having the same issue, it's cause Convex Auth doesn't work in SSR for remix and loader runs on the server. I still haven't figured out a nice way to handle the auth in remix yet though. Would also love to know if there is a solution for this as well!
ballingt
ballingt4w ago
How are you calling the function from the client, with the HTTP interface client? With preloadQuery? In the browser the ConvexReactClient is usually passed an auth token by configuring it with another React component from the auth provider. On the server you need to pass the auth token as a string. I see @Eyal Alfasi using const convex = new ConvexClient(CONVEX_URL); so they'd want to add convex.setAuth(identityTokenFromSomehwere)
sonandmjy
sonandmjy4w ago
@ballingt yes I did have a play around with the ConvexReactClient as well but I think there isn't a place we can get the identityToken yet while using Convex Auth hmm, I tried doing some redirects on the client like this
export function Authenticated({ children }: { children: React.ReactNode }) {
const { generatePath } = useLocale();

return (
<>
<AuthLoading>
<div className={"flex justify-center items-center h-screen"}>
<LoadingSpinner size={36} />
</div>
</AuthLoading>
<ConvexUnauthenticated>
<Navigate to={generatePath(routes.signIn)} />
</ConvexUnauthenticated>
<ConvexAuthenticated>
<AuthenticatedProvider>{children}</AuthenticatedProvider>
</ConvexAuthenticated>
</>
);
}
export function Authenticated({ children }: { children: React.ReactNode }) {
const { generatePath } = useLocale();

return (
<>
<AuthLoading>
<div className={"flex justify-center items-center h-screen"}>
<LoadingSpinner size={36} />
</div>
</AuthLoading>
<ConvexUnauthenticated>
<Navigate to={generatePath(routes.signIn)} />
</ConvexUnauthenticated>
<ConvexAuthenticated>
<AuthenticatedProvider>{children}</AuthenticatedProvider>
</ConvexAuthenticated>
</>
);
}
but sometimes the behaviour is a little weird. Eg. It might trigger the ConvexUnauthenticated first -> bounce me to the sign in page and I have another <Unauthenticated/> wrapper that might bounce me back to the authed page
ballingt
ballingt4w ago
Do you have a repro of this weird behavior? It'd be great to open an issue on the convex auth repo so we can solve it. Ah I see, on the server it's hard to know how to get the JWT without using Next, we ought to file another issue for that. TanStack Start will probably be first but Remix is possible after that!
sonandmjy
sonandmjy4w ago
ok let me try and make a repro for you! I looked at some of the issues and chats I think there has already been some requests for a remix adapter for convex auth
sonandmjy
sonandmjy4w ago
@ballingt Oh, I think I realised why while creating the reprod. You have to use SPA mode in remix in order for the client <Navigate/> to work. On first load into the page the behaviour of Navigate is a bit weird and gives me a 404 until I refresh + throws this error messasge in the terminal. In the server mode, the redirects should happen in the loader. So in order to use convex auth without a server adapter probably have to forego using loaders in remix for now unfortunately. So I guess it's not rly a convex bug
No description
ballingt
ballingt3w ago
ballingt
ballingt3w ago
If you want to describe what we need or copy in this convo could be useful
sonandmjy
sonandmjy3w ago
sure I'd be happy to do that. Thanks Tom
jamalsoueidan
jamalsoueidan3w ago
@sonandmjy please add comment or something-- @Eyal Alfasi same to you, spam the github issue 🙂
ballingt
ballingt3w ago
You can subscribe without commenting too, but comments about what you want from this are helpful too
jamalsoueidan
jamalsoueidan3w ago
We just need the token in the remix loader 🙂
sonandmjy
sonandmjy3w ago
alright, I've explained a bit more and linked this conversation to it. Hope to see it soon and happy to work on it too if you guys give me some pointers! Thank you
jamalsoueidan
jamalsoueidan3w ago
In the Next.js implementation the cookie is set in https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/cookies.ts#L75 in the Next.js implementation because it sets cookies https://github.com/get-convex/convex-auth/blob/main/src/nextjs/server/index.tsx#L250-L254 @ballingt already pointed up in the github issue, the nextjs/server/index file act as middleware 🙂 @Eyal Alfasi I solved the issue by creating a custom SECRET_KEY, so in case the user is not logged in, I would send a secret key from remix to convex, and doing so, the convex function will act as regular api call that require API_KEY instead of user logged in. You can do that until convex choose to develop convex-auth for remix 🙂