See @workos/template-convex-nextjs-authkit for the recommended Convex + AuthKit template; this repo is for discussion and testing.
link to example hosted on Vercel
To get this running locally follow the instructions at the repo above.
Both views use eagerAuth: true
in middleware.ts to make an access token available immediately on render.
The root route / does Convex authentication client-side, similar to what is used in a zero-backend React SPA.
During SSR no content renders, regardless of whether the user is logged in.
After hydration the client requests a JWT if AuthKit says the user is logged in.
- middleware.ts lists '/' as an "unauthenticated path" so AuthKit middleware will allow this route to render for logged-out users
- app/page.tsx uses
<Authenticated>
,<Unauthenticated>
, and<AuthLoading>
wrapper component to load different content and, critically, to wait to load content until the Convex client has a JWT
/server requires auth and renders authenticated content immediately.
During SSR the user must be authenticated and authenticated queries can be made.
After hydration a new JWT is requested and queries start to run once a JWT is received (due to expectAuth: true
).
- middleware.ts causes '/server' to only render for logged-in users
- app/page.tsx calls
withAuth()
which opts this route out of static rendering and into dynamic rendering by accessing cookies in its implementation. This page does not use<Authenticated>
to prevent authenticated queries from running.
/server doesn't use the <Authenticated>
component, so if an auth refresh ever fails its out of luck: the queries will render anyway.
Reproducing this is inconsistent.
Today <Authenticated>
content never runs during SSR, during SSR the auth state is always "unauthenticated" or "loading." If <Authenticated>
could be used during SSR then
- server pages could take advantage of better logged-out behavior (unmount instead of query errors)
- there'd be less flashes
Specifying { expectAuth: true }
requires different code for different routes and unfortunately blocks all queries, not just authed ones.
It also doesn't work as well as <Authenticated>
for switching between different auth token fetchers (see get-convex/convex-js#82).
- could we determine this based on some other list of authed routes, like in middleware?
- should a special argument to
useQuery()
hooks annotate whether they require auth? Opt-int could go the other way. (see get-convex/convex-js#69) - (deeper convex changes) to make the above work better could public functions declare their auth needs with typed middleware?