Skyguy
Skyguy3w ago

Server-side token forwarding for AuthKit + Convex in Next.js

I’m using @workos-inc/authkit-nextjs middleware (now called proxy) with Convex in a Next.js App Router project. On the client side, everything works — ctx.auth.getUserIdentity() returns a user after login. My question: Does AuthKit middleware automatically forward the session token for server-side calls to fetchQuery / preloadQuery, or do I need to pass { token } every time manually? I saw the changelog stating "No extra wiring or token exchange needed.", but I'm gueesing that's meant for client-side functions? Anyway, I can’t find clear docs about usage in server components and routing. Thanks in advance for any clarification!
4 Replies
Convex Bot
Convex Bot3w 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!
erquhart
erquhart3w ago
Yeah for server side you have to pass the token Definitely an improvement opportunity there, though
Skyguy
SkyguyOP3w ago
I see, thanks. Should I add the tag feature request? Or should I add it as an issue on github? if anyone needs simple helpers
import "server-only";
import { ArgsAndOptions, FunctionReference } from "convex/server";
import { fetchQuery, NextjsOptions, preloadQuery } from "convex/nextjs";
import { withAuth } from "@workos-inc/authkit-nextjs";

export async function fetchQueryWithAuth<
Query extends FunctionReference<"query">,
>(query: Query, ...rest: ArgsAndOptions<Query, NextjsOptions>) {
const [args, options] = rest;
const { accessToken } = await withAuth({ ensureSignedIn: true });
return fetchQuery(query, args, { ...options, token: accessToken });
}

export async function preloadQueryWithAuth<
Query extends FunctionReference<"query">,
>(query: Query, ...rest: ArgsAndOptions<Query, NextjsOptions>) {
const [args, options] = rest;
const { accessToken } = await withAuth({ ensureSignedIn: true });
return preloadQuery(query, args, { ...options, token: accessToken });
}
import "server-only";
import { ArgsAndOptions, FunctionReference } from "convex/server";
import { fetchQuery, NextjsOptions, preloadQuery } from "convex/nextjs";
import { withAuth } from "@workos-inc/authkit-nextjs";

export async function fetchQueryWithAuth<
Query extends FunctionReference<"query">,
>(query: Query, ...rest: ArgsAndOptions<Query, NextjsOptions>) {
const [args, options] = rest;
const { accessToken } = await withAuth({ ensureSignedIn: true });
return fetchQuery(query, args, { ...options, token: accessToken });
}

export async function preloadQueryWithAuth<
Query extends FunctionReference<"query">,
>(query: Query, ...rest: ArgsAndOptions<Query, NextjsOptions>) {
const [args, options] = rest;
const { accessToken } = await withAuth({ ensureSignedIn: true });
return preloadQuery(query, args, { ...options, token: accessToken });
}
I’ve found an additional, subtle race condition when using Convex with AuthKit. If I preload a query that requires auth (server-side with { token }) and then pass it to usePreloadedQuery, the initial server render works fine. But when hydration happens, the Convex client may not yet have authenticated over the websocket — so the re-subscribed query fails on the client side. Basically the preloaded query runs before the Convex client has a valid token. I can work around it by wrapping the client component in an AuthGate that waits for useAuth() to finish, but I figured this might be worth reporting.
erquhart
erquhart3w ago
This isn't authKit specific, have to hold preloaded results in client state to render until client auth resolves

Did you find this page helpful?