Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/get-convex/better-auth/llms.txt

Use this file to discover all available pages before exploring further.

Showing UI based on authentication state

You can control which UI is shown when the user is signed in or signed out using Convex’s <Authenticated>, <Unauthenticated> and <AuthLoading> helper components. These components are powered by Convex’s useConvexAuth() hook, which provides isAuthenticated and isLoading flags. This hook can be used directly if preferred.
Use Convex’s authentication state components or the useConvexAuth() hook instead of Better Auth’s getSession() or useSession() when checking whether the user is logged in. Better Auth will reflect an authenticated user before Convex does, as the Convex client must subsequently validate the token provided by Better Auth. Convex functions that require authentication can throw if called before Convex has validated the token.
In the following example, the <Content /> component is a child of <Authenticated>, so its content and any of its child components are guaranteed to have an authenticated user, and Convex queries can require authentication.
src/App.tsx
import {
  Authenticated,
  Unauthenticated,
  AuthLoading,
  useQuery,
} from "convex/react";
import { api } from "../convex/_generated/api";

function App() {
  return (
    <main>
      <Unauthenticated>Logged out</Unauthenticated>
      <Authenticated>Logged in</Authenticated>
      <AuthLoading>Loading...</AuthLoading>
    </main>
  );
}

const Content = () => {
  const messages = useQuery(api.messages.getForCurrentUser);
  return <div>Authenticated content: {messages?.length}</div>;
};

export default App;

Authentication state in Convex functions

If the client is authenticated, you can access the information stored in the JWT via ctx.auth.getUserIdentity. If the client is not authenticated, ctx.auth.getUserIdentity will return null.
Make sure that the component calling a query that requires authentication is a child of <Authenticated> from convex/react, or that isAuthenticated from useConvexAuth() is true. Otherwise, it will throw on page load.

Getting the current user

There are two ways to get the current user in a Convex function:

authComponent.getAuthUser(ctx)

Returns the full user object with session validation. Throws if unauthenticated. Use this when you need the full user record and want to enforce authentication.

ctx.auth.getUserIdentity()

Returns the identity from the JWT without validating the session against the database. Returns null if not authenticated. Lighter weight, but does not confirm the session is still valid.
convex/messages.ts
import { query } from "./_generated/server";

// You can get the current user from the auth component with session validation.
export const getCurrentUser = query({
  args: {},
  handler: async (ctx) => {
    return await authComponent.getAuthUser(ctx);
  },
});

// You can also just get the authenticated user id as you
// normally would from ctx.auth.getUserIdentity. Note that
// this does not validate the session.
export const getForCurrentUser = query({
  args: {},
  handler: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (identity === null) {
      throw new Error("Not authenticated");
    }
    return await ctx.db
      .query("messages")
      .filter((q) => q.eq(q.field("author"), identity.email))
      .collect();
  },
});