Skip to main content

Custom User Fields

Place user data in the session, Better Auth component, JWT, or application projection deliberately.

Choose the field's source from how it is written, read, and refreshed.

Decision table

RequirementStore/read from
Auth-domain field managed with the userBetter Auth user/additional fields
Small field needed during SSR immediatelySession user when appropriate
Small field needed in every Convex identityJWT claim
Frequently changing product profileApplication Convex projection/table
Role or membership used for authorizationCanonical backend data checked by the function

Better Auth additional fields

Define the field in server Better Auth options and infer it in the client definition using the Better Auth-supported client mechanism for the pinned version. Confirm the value appears at runtime; TypeScript inference alone does not populate it.

JWT claims

The Convex plugin can define a payload:

convex/auth.ts
convex({
  authConfig,
  jwt: {
    definePayload: ({ user }) => ({
      name: user.name,
      image: user.image ?? undefined,
    }),
  },
})

JWT values remain unchanged until a new token is issued. Do not use a long-lived claim as the only source for revocable permission.

Application projection

Use a projection for product-specific fields, search indexes, or joins in Convex. Mark it as derived and provide a rebuild path.

ts
const profile = useConvexUser(
  api.users.getCurrent,
  {},
  {
    source: 'projection',
  },
)

The projection does not become session truth. Better Auth deletion and update flows must synchronize or rebuild it.

Module augmentation

Use augmentation only to describe runtime fields that are already guaranteed by your configured JWT/session contract. Never add a TypeScript field to make an absent runtime value appear supported.