#Check for auth when using workos
7 messages · Page 1 of 1 (latest)
When using WorkOS AuthKit with Convex, the proper way to check authentication state is to use Convex's useConvexAuth() hook (or the <Authenticated> / <Unauthenticated> helper components) — not WorkOS's own useAuth() hook — when you need to gate access to authenticated content or Convex queries.
Here's why and how:
Why not WorkOS's useAuth()?
WorkOS's useAuth() tells you if WorkOS knows the user is logged in, but it does not guarantee that the Convex client has fetched and validated the auth token with your Convex backend. Using useAuth() alone can result in isAuthenticated: true on the WorkOS side while Convex still considers the user unauthenticated. [Convex docs]
"It's important to use the
useConvexAuth()hook instead of AuthKit'suseAuth()hook when you need to check whether the user is logged in or not. TheuseConvexAuth()hook makes sure that the browser has fetched the auth token needed to make authenticated requests to your Convex backend, and that the Convex backend has validated it." [Convex docs]
Proper approach
1. Wrap authenticated content in <Authenticated>
Use Convex's <Authenticated> component to conditionally render content only when the Convex backend has confirmed the user is authenticated:
import { Authenticated, Unauthenticated } from "convex/react";
export default function Home() {
return (
<div>
<Authenticated>
<Content /> {/* Safe to make authenticated Convex queries here */}
</Authenticated>
<Unauthenticated>
<p>Please sign in to view data</p>
</Unauthenticated>
</div>
);
}
2. Use useConvexAuth() if you need the boolean directly
import { useConvexAuth } from "convex/react";
const { isAuthenticated, isLoading } = useConvexAuth();
3. In Convex functions, use ctx.auth.getUserIdentity()
On the backend, check auth via ctx.auth.getUserIdentity(). Make sure the component calling the query is wrapped in <Authenticated> to avoid errors on page load:
export const listNumbers = query({
args: { count: v.number() },
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
throw new Error("Not authenticated");
}
// ...
},
});
Common pitfall from the community
A recurring issue in the Discord thread was that isAuthenticated from useConvexAuth() returned false even though WorkOS's useAuth() showed a logged-in user. This is typically caused by misconfiguration (e.g., missing aud claim, wrong auth.config.ts, or not running npx convex dev after changes). [AuthKit troubleshooting]
Also, the loading state from WorkOS's useAccessToken hook can be unreliable — a community-suggested fix is to also check !accessToken in your loading boolean to avoid briefly sending an empty auth token. [Discord thread]
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@tough crypt Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@desert night export default authkitProxy({
Let me check the knowledge base for you again. One moment! :books:
The knowledge sources do not contain any information about authkitProxy or an export default authkitProxy({...}) pattern. The middleware setup documented in the knowledge sources uses authkitMiddleware from @workos-inc/authkit-nextjs, not authkitProxy.
The documented middleware setup looks like this:
import { authkitMiddleware } from '@workos-inc/authkit-nextjs';
export default authkitMiddleware({
middlewareAuth: {
enabled: true,
unauthenticatedPaths: ['/', '/sign-in', '/sign-up'],
},
});
export const config = {
matcher: [
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
'/(api|trpc)(.*)',
],
};